Monday, May 30, 2016

Lloyd's Video Analysis Tool: Now in the Mac App Store




Yes, Lloyd's Video Analysis Tool, an app I started over two years ago was just accepted by Apple and is now in the Mac App Store. It took three tries to get it in and although there was much frustration and anxiety associated with the first two rejections, I learned a great deal about many things, some of which I'll try to summarize briefly in this post.

First, some words of thanks to two people in the LiveCode community who helped me get through the last grueling quarter mile on this project: Klaus Major and Jacqueline Landman Gay. I also need to send special thanks to Sam Rowlands of Ohanaware. Apple found a bug in my app the second time they reviewed it which led me to a very confusing journey into the world of Apple's sandboxing approach to apps. I was finally able to understand the problem well enough to come up with a workaround thanks to their help. While on the subject of Ohanaware, they make a fantastic product called App Wrapper 3 that I heartily endorse. It "wraps" your app with Apple's developer certificates and automatically gets the app ready for uploading to Apple's iTunesConnect. I'll be purchasing a yearly subscription from here on out at a very reasonable cost of only $49.99. (Please note that was an unsolicited and unpaid endorsement!)

A Question I Had Long Pondered: Do I Even Want to Submit to the Mac App Store?


To be honest, I knew submitting to the Mac App Store would probably be a hassle given my previous experience submitting iOS apps to Apple. One has to figure out the whole "Apple certificate thing." Plus, I knew already that it was going to be a struggle to figure out how to then add the proper certificates to my Mac app because, unlike iOS apps, LiveCode does not provide a way to do it as part of the standalone creation process. (As it turned out, App Wrapper 3 made this step incredibly easy.) I also didn't know if my $99 annual Apple developer fee for iOS apps would count for Mac App (as it turns out, it did). In anticipation of all of this, I had done some research on "alternatives to the Mac App Store" and found a company called FastSpring. I like the company and so far they have provided great support. Now that my app is in the Mac App Store, I'm reviewing my options at this point. I still might offer the app for purchase at FastSpring also, assuming it doesn't violate some Apple policy. I already know that FastSpring is fine with me selling on the Mac App Store. FastSpring also did not require the Apple developer certificates, though I knew this would tremendously impact my sales as the app would then not be "recognized" by anyone Macintosh as coming from a "trusted" source due to way Apple's Gatekeeper software works. My point here is that FastSpring has been very easy to work with and flexible. I think further exploring a relationship with them will teach me more about the business side of app development, which I think my students will be interested in knowing more about.

But, I'm getting ahead of myself in telling this story. To back up, I was pleasantly surprised to be able to successfully acquire the needed development and distribution certificates from Apple. And, thanks to App Wrapper 3, I was able to easily add these to my app and produce a downloader file suitable for uploading to iTunesConnect. So, I decided I would just to submit a "lite" version of my app to Apple and sell the app itself on FastSpring.

I was also ambivalent about what to do for Windows users. Almost all of the problems reported by my beta testers over the past year have been about the Windows version. I didn't want to sell something to people if I wasn't confident it would work. All my development and testing of the app was on the Macintosh for the Macintosh, but it's obviously very easy just to also export a standalone version of the app to Windows with LiveCode. And, it did work for Windows users most of the time (as my students who are Windows users reported). So, a few months ago I decided that I would sell only the Macintosh version but the purchase would also come with a free (though unsupported) copy of the Windows version. That is, I would make it clear you were buying the Macintosh product and the "toy inside" (to use a breakfast cereal metaphor) was a free Windows copy. I felt this was ethical and met my own standard of "truth in advertising."

Mac App Store Rejection 1


First, I want to point out that I received feedback from Apple within about two hours of submitting the app the first time. Despite the fact that the app was rejected, I was very grateful for the quick turnaround.

Two reasons were given for the rejection. First, it appeared to the reviewer that it was a demo app and these are not allowed by Apple. I knew that going in and actually made the case in my "Notes to the Reviewer" when I submitted the app that this "lite" version was not a demo in that one could use the app to do real work even though the app intentionally had limited functionality. However, the reviewer still felt I was in violation of Apple's policy, but also gave me feedback that this objection could be overcome simply by indicating that another app would have to be purchased for complete functionality. Even though I felt had already done this, I apparently put this information in the wrong place. OK, so that objection could be easily surmounted.

The second reason for rejecting the app was that "the app enables additional functionality in a non-standard manner. Enabling features within the app with mechanisms outside of the App Store is not permitted." The reviewer is referring to the "unlocking" strategy I created on my own (click here to read about that). I obviously wasn't surprised that this strategy was termed a "non-standard manner," but I didn't think it would be a show stopper. I think the key phrase is "outside of the App Store" because obviously Apple wants all purchases to be made inside so that Apple gets their share.

After sleeping on it, I decided to just go ahead and submit a fully functional app to the Mac App Store. I submitted it around Noon last Sunday.

Mac App Store Rejection 2


Apple responded that they had rejected the app at about 10 pm Sunday evening. Three reasons were given: 1) the app wasn't "sandboxed appropriately"; 2) there was some discrepancy in how I named the app in various places in the submission process; and 3) "Apps that exhibit bugs will be rejected." Reasons 1 and 2 were easy to deal with, but a bug? The reviewer was nice enough to send me a screenshot of the error with a description of what s/he was doing at that moment, which was very helpful. Here's the screenshot:



This screenshot shows LiveCode's "Bug Report" dialog box that I wisely incorporated into the app some time back. Unfortunately, the Apple reviewer did not actually choose to send me the bug report. So, I spent the next day trying to recreate the error.

I actually was able to recreate the error rather quickly given that I knew where to look based on the reviewer's feedback. It was a "division by zero" error, something I had seen before when the video didn't load properly. The reason for the error is that I use a little custom formula that uses the duration of the movie in the denominator. If the movie doesn't load, this value is 0, hence the error. But, I had never seen the error before under these circumstances. Thus began a three day journey into discovering why.

Troubleshooting the Bug


Although I'm tempted to really get "into the weeds" at this point, I'll just jump to the cause and the solution. This is again where I need to thank Klaus, Jacque, and Sam. Without their timely responses to my calls for help, I would still be scratching my head. (If you want to read my detailed description of the error and the troubleshooting that ensued with Klaus, Jacque, and Sam, you can click here to read all about it in my posting to LiveCode's Mac OS forum.)

The problem was rooted in how Apple's sandboxing technology works. I already knew that all "apps were islands" in iOS and Mac OS, so I wasn't trying to write anything outside of the app's sandbox area. But the app does need to read outside the sandbox to get the path to the project video. This path is then stored correctly within the walls of the sandbox. But here was the really confusing part - the app successfully "found" the video outside of the sandbox, but it wouldn't load it. I just couldn't wrap my head around this because the user obviously had successfully been able to get the video to work when the project was first created. Why wouldn't it work now? I became even more confused when I discovered (after a few hours) that if I created a second video analysis project from scratch using exactly the same video, the first, older project would now work! But, if I quit the app and restarted, both stopped working ... unless I created a third project from scratch that also used the same video.

So, I figured the problem had something to do with Apple's sandbox technology. I initially put the blame on LiveCode's Player object. Sam explained to me what was needed to solve this problem, namely the programming some some key "entitlements" into the to allow it to access to the user's main area on the hard drive. Unfortunately, Jacque explained that this solution wasn't possible with LiveCode. I am so grateful to have learned this from Jacque because I likely would have spent many more days trying to figure it out. The solution I finally used is really just a workaround. I discovered that I could "reconnect" an old project to the video simply by asking the user to "confirm" the location and name of the project's video using LiveCode's "answer file" command. It was easy to include in the script the name of the video plus opening the video's enclosing folder in a dialog box. The user simply had to click to confirm the video. This re-established the link to the video and the link was sustained as long as the app was running. Yes, this added a little bit of inconvenience to the user, but there really was no other way to solve the problem.

Third Time's a Charm


I made the modifications along with a few last minute improvements to other parts of app, then submitted my third version to iTunesConnect around 1:00 pm on Friday. I tried to do other work after that, but I found myself checking for email from Apple every few minutes. As the afternoon rolled into the evening, I began to think those earlier speedy turnarounds from Apple were flukes. And, this was the Friday before Memorial Day weekend - the unofficial start to summer here in the USA - so I worried I might have to wait until Tuesday at the earliest to get a reply.

Interestingly, I mentioned to my wife around 7:30 pm that given that Apple's headquarters were in Cupertino, California, perhaps the reviewer was also on "California time" making it was only 4:30 there. I joked that the reviewer would say to him/herself "Maybe I'll review just one more app before my long weekend" with my app being the next one in line. Well, at 7:49 pm, I received an email indicating that my app was now "In Review." Then, at 8:50 pm I received word that my app had been approved!

Giving Out Free Copies


I've also updated the Web site for "Lloyd's Video Analysis Tool" where people can download the free version of the app to check it out before purchasing. This free version still has the "upgrade" feature that unlocks the app with the right secret code to give it full functionality. As I long planned, this will be my way to give out free copies of the app to people of my choice, such as my beta testers, all students and faculty in the College of Education at the University of Georgia, and definitely to Klaus, Jacque, and Sam. I designed the free version so that it would likely be more than sufficient for use by my colleagues who are requiring some sort of video analysis by their students as a course requirement. Having a functional, free version that teachers could use was important to me. I'm not worried about making money on this app, but then again, I'm not opposed to it either.

Final Thoughts


There is so much else I learned that I could write about here. And maybe I will since I took good notes (as always). My understanding of Apple certificates is clearer to me than before, though this still remains fuzzy. This process, at least to me, is about 5% intuitive and 95% memorization (hence the need for good notes). This is the kind of process one tends to learn by repetition. Fortunately, I have several other apps I'd like to wrap with certificates so that Gatekeeper will "trust" them when I ask my students to download and install them.

Now you might be asking how you can get a free copy of the app. Well, if you buy me a beer or two (or three) the next time we meet, that might do it. But, given that the app only costs $7.99 you will probably save quite a bit of money by just buying the app outright!


Sunday, April 17, 2016

Creating a Web Page Pinging Tool with LiveCode to Check a Web Site's Status

Recently, I've been experiencing a lot of trouble with my web hosting company. I won't identify the company... yet ... as I think they may have finally solved the problem. But, suffice it to say that the problem was chronic and severe to the point that I was considering dropping this company after about 10 years of being a loyal customer. The problem was that my web site was experiencing frequent, intermittent periods of down time. Everything was working fine one minute, then the next I was getting the message "Service Unavailable." Two minutes later, all was fine. To the company's credit, each time I submitted a problem ticket they got on it right away and reported back within an hour or two that they had "found the problem and fixed it." To their discredit, they hadn't. I was submitting help tickets over and over with the company coming back each time to tell me that now all was well, when it really wasn't.

The seriousness reached its peak for me when my web site failed to work properly during a research session about two weeks ago while using my Q Sort tool. I had been experiencing system outages the day before and the morning of the research session. A few hours before the research session was scheduled to take place, the company reported that they had "really" found the cause of the problem this time and all was well. For the next few hours, it did seem like all was working fine. But, during the roughly 20 minutes of the research session, about half of the participants experienced Internet problems. This research session was done during a graduate class and everyone -- including me -- thought that the problem was likely due to some bug in my software. (I had made major updates to the software in preparation for this research session. Happily, my Q sort tool actually seemed to work perfectly.) There is nothing worse to a researcher than to lose data after all the time it took to arrange and plan the session.

I again reported the problem to the company and again looked they into it and again they said they had fixed the problem. I then traveled to attend the AERA conference in Washington, DC and put this issue on the back burner. But when I returned to Georgia and began working on the web site, I found the site was down -- very frustrating. Again, to the company's credit, they steadfastly looked into the problem. Perhaps due to an angst-filled trouble ticket message, they moved my site to a different "application pool," and so far everything has been working fine. Of course, given my lack of confidence I found myself obsessively checking the web site over and over throughout the day. And then it occurred to me -- I could program my own tool to "ping" the web site repeatedly and review the result later. If the web site wasn't working at some point, I could then share my data log with the company to aid in their troubleshooting.

Lloyd's Web Site Pinging Tool


I created a LiveCode stack that pings a given URL every so many seconds to see if it returns an expected result or an error. It's important to remember that if you ping just any old web page, you are going to get a bunch of HTML code as the result, and probably a lot of it. So, I created a very simple PHP page that pulled one small piece of data from the mySQL database along with the following message: "Ping Successful." I also did not use any HTML formatting, so the result was a single line of text. Getting this result let me know that everything on my site was likely working fine.

I also put a date/time stamp at the beginning of each result line. If there was a problem, this would tell me exactly when and for how long the problem persisted.

The great thing about this little app is that even though I might check the web site manually and find everything was working, given the intermittent nature of the problem the thought quickly entered my head "Sure, it's working now, but just wait a minute!" Seeing a data log that ran all night or all day showing no problems is real evidence that the problem has indeed been fixed.

Here's a screen shot of the program after pinging my site every 15 seconds for just two minutes:



You can enter any URL you want and any time interval you want. When you start pinging, the live data stream is shown in the field "Live Pinging Data." When you stop the pinging, the data are automatically copied and pasted into the field "All Data." If you start pinging again, all the "live data" are cleared out as the new pinging session begins. The phrase "New Session" is added at the beginning of any new pinging data session to make each session's data easier to spot.

How It Works


The main code is in the button "Start Pinging:"

 global varDataURL, varCheckResponses, varTime  
   
 on checkResponses  
   put the internet date&comma&URL varDataURL after field "log"  
   if varCheckResponses is true then   
    send checkResponses to me in varTime seconds  
   else  
    put "New Session"&return&return after field "log2"  
    put field "log" after field "log2"  
   end if  
 end checkResponses  
   
 on mouseUp  
   put line 1 of field "time to check" into varTime  
   put empty into field "log"  
   put field "URL" into varDataURL  
   put true into varCheckResponses  
   checkResponses  
 end mouseUp  

I created a custom procedure called "checkResponses" that loops as long as the variable "varCheckResponses" is true.  The loop is based on the "send to me" strategy.

All the button "Stop Pinging" does is set "varCheckResponses" to false.

So Far So Good


I'm happy to report that based on the data collected by my pinging tool, my web site has been completely stable for about 48 hours. I ran my program overnight the first day and for a few hours here and there over the next day. My web site might be -- just maybe -- fixed.

So, for now, I'm sticking with the company.

Oh, one more thing. This problem motivated me to learn how to move mySQL data from one web site to another, something I've never done before. I have a PHP/mySQL web site account on one of the servers at my University, so I was going to move everything there if the problem persisted. I had always wondered how difficult it would be to migrate a mySQL site, but never actually learned the steps.

Saturday, March 26, 2016

Lloyd's Weekend STEAM Project Using LiveCode

It was Friday around 5 pm after a long day of meetings and I again had the urge to do something creative as I ended the week. I had seen a compelling video on the Physics & Astrophysics facebook page a few days earlier that captured my attention and the thought occurred to me that I could recreate it with LiveCode. That became my weekend project. I think this is a nice example of a small STEAM (science, technology, engineering, arts, and mathematics) project. I'm a big advocate of adding the arts to STEM initiatives because, as humans, we yearn for beauty and there is much beauty in mathematics and science.

Here's an animation of my project:

I titled the project "circle within circle" because that's exactly what it looks like. However, amazingly, the red marbles are moving in straight lines, not curves. Here is a second animation to prove it:


I See the "A," But Where is the Rest of "STEM"?


The challenge to creating this project - and what was most fun - was figuring out where each marble should start and end. The circle has a radius of 200 pixels with its center located at the screen location of 400,300. (It's important to remember that the 0,0 origin of the computer screen is not the center of the screen, but the top left corner. And, unlike the traditional cartesian coordinate system, the vertical y-axis is positive in the downward direction.) It's easy enough to figure out where the marbles should start and end on the vertical and horizontal lines, but what about those at the various angles, such as 45 degrees? Ah, this calls for a quick refresher of sine and cosine. If just the mention of these two math concepts brings back horror-filled days from high school geometry, then it is high time you revisit them and see them instead as things of beauty. Here's a nice illustration of what they are all about:



As you can see, the cosine is simply the horizontal distance from the center of the circle to the point on the circle matching a given angle. The sine is just the vertical distance. Notice the right triangle that gets formed with the hypotenuse shown in red depicting the angle. We can use the good 'ol Pythagorean Theorem - a2 + b2 = cto figure out the lengths of the horizontal and vertical lines. And voilĂ , we have the x and y coordinates.  Most people are a little surprised that a 45 degree angle does not produce x and y coordinators of half the distance of the radius, but instead the distance is .707 of the radius.

Here's an illustration of my LiveCode screen that shows how to figure the starting point for the marble at the 45 degree mark:



Using a radius of 200, the length of the x and y (horizontal and vertical) is 141.4 (i.e. 200 X .707). Figuring the x coordinate is straightforward: 400 + 141.4, or 541 rounded to the whole number. Calculating the y coordinate is a little trickier because of that pesky detail of the 0,0 origin being in the top left corner of the screen. We actually need to figure out how to much to add to the top boundary of the circle, which is 100. So, we have to subtract 141.4 from 200 to get 58.6. We add 58.6 to 100 to get a y coordinate of 159 (again rounded to the nearest whole number).

I then had to use the same logic to figure out all of the other locations for the remaining marbles given their respective angles. Yes, lots of great math going on here! 

My use of a computer programming language (i.e. LiveCode) is the technology part of my STEAM project. And, I'll admit I don't have any engineering or science components yet, but I'm sure you could come up with a few ideas. What comes to my mind is how an internal combustion engine works - the pistons are going in straight lines, which then turn the crankshaft:


But It Doesn't Look Quite Right


Now, you might say: "Lloyd, those marbles aren't exactly creating a circular motion. There is a bit of a hump. And I took a look at the video link you provided above - great background music, by the way - and its animation looked like a perfect circle." Alas, you are correct, and I'm a little befuddled as to how to smooth out the hump. I thought it might have something to do with the timings, but I don't think so. Of course, you might see immediately what needs to be done to make the marbles seemingly move in a perfect circle, so do remember to email me after you figure it out. (Below is my code to help you.)

But hey, this was only a weekend project and I think there is just as much beauty in my imperfect version. 


   put 2 into varTotalSeconds  
   put .25 into varHoldSeconds  
   repeat until the mouseclick  
    //motion 1  
    move graphic "ball1" to 400,500 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball2" to 324,486 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball3" to 258.6,441 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball4" to 216,376 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball5" to 200,300 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball6" to 216,224 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball7" to 258.6,158.6 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball8" to 324,116 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    //motion 2        
    move graphic "ball1" to 400,100 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball2" to 476,116 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball3" to 541,158.6 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball4" to 584,224 in varTotalSeconds seconds without waiting     
    wait varHoldSeconds second  
    move graphic "ball5" to 600,300 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball6" to 584,376 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball7" to 541,441 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
    move graphic "ball8" to 476,484 in varTotalSeconds seconds without waiting  
    wait varHoldSeconds second  
   end repeat  

Thursday, March 17, 2016

The Best and Worst of LiveCode Troubleshooting

I am very behind in writing about my various LiveCode projects, particularly my Q Sort project. So I'll use this post to write about a few experiences I have had lately. Yes, this blog post is all about the art and science of troubleshooting. I'll start with a shining example, and then close with a problem that I remain unable to resolve. However, this problem has nudged me into a new direction for my Q Sort tool that really was inevitable, namely moving from an FTP approach to using text files to store data to the use of a mySQL database.

Troubleshooting Example 1: The Case of the Missing Data


In almost all of my field tests using my Q Sort tool, I had been experiencing an unusual problem of missing data. The problem was very spotty. The data from most responses were fine, but there would always be a handful (i.e. 2 or 3 out of 20 people) with missing data. Most of the time, only one data point would be missing, but it was possible that 2, 3, or even 4 data points could be missing. At first, I thought it might be some artifact of the FTP process, such as some data getting "lost in transmission," but that seemed like a weak and unlikely theory.

Also, another person who completed a Q sort - a doctoral student in my department - was also adamant that a statement she rated one way was subsequently rated a different way when she reviewed her data. No one else had ever noted this before, so I knew it was possible she was just mistaken or confused. However, she sounded very sure of herself, so I was careful to note her observation because if she was right, then the accuracy of all the Q sort data would be in question. (I now think she was right. The fix I explain here solves that problem too.)

It wasn't clear to me how to go about troubleshooting this problem, given the rareness of its occurrence. I had never experienced the problem myself in all of my testing. My first idea was to set aside an hour in my design studio course at the University of Georgia and have the students do several Q sorts in a row with the hope that the problem would appear in someone's data. Then, I could compare the data uploaded to the web server with the data saved to their local computer. However, I solved the problem on my own in a relatively short amount of time.

My Solution: Make All Data Visible


To help figure this out, I made a copy of the Q Sort tool just for troubleshooting. I turned off all of the FTP and other data storing commands and made visible the key hidden fields that collected and managed the data while the Q sort was in progress. As I played with doing a bunch of Q sorts, I discovered the problem.

Basically, here is what was happening. Two statements in adjacent slots would be appropriately "locked" into their slots. Then, the user would move one of these statements into the other slot. The just emptied slot would correctly then register "empty." But, if I then moved the other "locked in" statement into the now vacated slot, both slots would register that statement. The other consequence to this would be that if all other slots were filled, the "Submit" button would be activated, thus allowing the user to then quit and upload their data. This problem wouldn't occur, or would resolve itself if it had, if the person moved one of these statements back to the main area of the screen. So, the problem only occurred under these fairly rare situations.

To fix this, I added some code to the "on mouseUp" script in the button "statement template" to check for duplicate statement numbers in the field "slot contents." Even this was a little tricky as I had to make sure that the correct slot showed where the statement now resided. To do this, I first added this code to look for EVERY occurrence of the button number and replaced it with "empty":

    //First check for duplicate statement numbers in field "slot contents" (the cause of the missing data problem) - February 21, 2016  
    //I adapted this code from the button "Check for Duplicates" from the Q sort analysis tool  
    put the number of lines in field "slot contents" into L  
    repeat with i = 1 to L  
      put item 1 of line i of field "slot contents" into varName  
      if SN = varName then  
       put "empty" into line i of field "slot contents"  
      end if  
    end repeat  
   
The key was to put this code BEFORE this existing line of code (near at the end of the mouseUp script) because this line then puts the button's location into the correct slot:

put SN into item 1 of line varSlotNumber of field "slot contents"

In summary, if a duplicate was found the appropriate one would remain but the other would be replaced with "empty."

Improving the Usability


But, I wasn't finished. As I played with the program I could sense a usability problem. As I moved statements previously locked into a slot to an adjacent slot, it was often not obvious which statement was no longer "locked" into a slot. I decided the best thing to do would be to "snap" the unrated statement out of the "slot zone" to the original starting x screen coordinate, but leaving it at the current y screen coordinate. To do this, I adapted the script that already existed in the "To far left" button and added it to the custom function "checkForEmptySlots" on the card "sort":

    //First check for duplicate statement numbers in field "slot contents" (the cause of the missing data problem) - February 21, 2016  
    //I adapted this code from the button "Check for Duplicates" from the Q sort analysis tool  
    put the number of lines in field "slot contents" into L  
    repeat with i = 1 to L  
      put item 1 of line i of field "slot contents" into varName  
      if SN = varName then  
       put "empty" into line i of field "slot contents"  
      end if  
    end repeat  


A key idea was to put this script near the end of the function and right before other script that checked to see if all statements were accounted for. If all statements were accounted for, only then would the "Submit" button be activated.

Note this important line (line 7):

 if not intersect (graphic "statement background", button locStatementName) then next repeat  

This line is important because I only wanted to "snap" out of the way those statements that were in the "slot zone."

The result is now a very clear user interface that shows which statements are "locked" into place and which are not.

Troubleshooting Example 2: The Case of the Deleted Data


OK, great. I solved a thorny problem all on my own. Just as I was finishing my victory lap, complete with champagne, another recurring problem surfaced. This problem remains unresolved and really has me stumped: Data that I know were correctly FTPed to my web server have subsequently vanished. I really have no explanation for this. It has happened occasionally and rarely. The first few times it happened, I blamed myself for just not remembering deleting the data. This was a reasonable explanation because in my early field trials, I would occasionally wipe the text file clean on my server. However, the last time it happened, I know I did no such thing.

To be honest, I know I haven't been using the preferred LiveCode libURL commands, such as libURLftpUploadFile, for the data transfer (here is a link to a good tutorial). Instead, I've simply been using the simple "put" command in tandem with the URL function:

 put field "ftp scores"&return after URL varUploadSite  

However, I don't see how this is at all related to the problem given that I know the data were in fact saved to the web server. So, I remain stymied. Perhaps someone reading this blog post with more experience than I knows what to look for. If so, I hope they will contact me.

But, as I mentioned at the start of this blog post, my inability to solve this problem has persuaded me to abandon the FTP method altogether and instead use a mySQL database for all data storage. I knew I would eventually make the jump to using a real database, but there was a certain charm and elegance to just using simple text files for all data storage. Interestingly, I reread one of my own blog posts from last year to relearn how to do this titled "Desperately Seeking Middleware." I hope to finish this transition to mySQL in the next week or so.

Final Thoughts


These two examples are good reminders of how coding can bring the "thrill of victory" and the "agony of defeat." Just when I thought I was rather clever in figuring out one problem, another jumps up and bites me. No worries, though, as this is all part of the learning experience. One day, I know I'll figure out that deleted data problem, or bump into someone who can help me.


Sunday, February 14, 2016

LiveCode Report from the Conference on Higher Education Pedagogy at Virginia Tech

I just returned from attending the Conference on Higher Education Pedagogy (CHEP) at Virginia Tech in Blacksburg, Virginia. This is the fourth year in a row I've attended. I think this is one of the best conferences about teaching I've ever attended. The venue is great, the sessions are high quality (and usually very practical), the people are interesting, helpful, and supportive, the cost is low ($25), and the food is great.

I did a LiveCode workshop on Tuesday and I also presented my current research project exploring how to adapt the Q methodology for instructional purposes (built with LiveCode). Some people also showed some interest in my video analysis tool, thanks to some shout-outs in sessions and on twitter by friends and colleagues, particularly David Carbonara and Sherry Clouser.

LiveCode Workshop at CHEP


I again presented my LiveCode workshop using the title "Introduction to Coding for Mere Mortals Using LiveCode." Although eight people had signed up, only three actually showed up. But that allowed me to give more personalized attention to them. My philosophy is that anybody can learn to code and I've designed my workshops for people who have never coded before. I think it went well. I used a "new and improved" Google workshop presentation. Besides helping to organize the workshop activities to keep me on task, I added many more links to good resources and videos.

We were able to complete two "LiveCode First Projects" in our three-hour workshop: Visit the USA; and Mad Libs. I like how both of these projects offer different programming experiences with LiveCode. The participants were very motivated up to the end. In fact, they were very interested in exploring some of the LiveCode Mini-Projects I've designed and wanted to try the hardest one of the bunch. So, we built the EZ Math Calculator.

A reminder to any of my UGA colleagues who might be reading this that I'll be offering two LiveCode events this semester. First, I'll be offering a short, 90 minute workshop about LiveCode for UGA's Center for Teaching and Learning on March 22, 2016 from 10:00-11:30 in Room 372 of the Miller Learning Center. Due to the short length of the session, this will likely need to be mostly demonstration, but I hope to have at least one hands-on activity. Second, I'll be conducting a short course on learning to program with LiveCode for the OLLI beginning February 23. This course will consist of four sessions (February 23, 25, March 1, 3) scheduled from 1:00-3:45 in Room 143 River's Crossing. I'm very excited by this because it will give me an extended period for teaching LiveCode. The pace will be very relaxed. I don't know OLLI's policy for others to attend, so check with them if you are interested.

Adapting the Q Methodology for Instructional Purposes


Most of the sessions at CHEP are given by higher education faculty and instructors who offer practical ideas and suggestions for teaching in higher education gained from actual experience in the classroom. However, there is also a smaller research track at the conference, within which I presented my Q sort work. Unlike the other sessions, research sessions feature two presentations within the 50-minute slot. So, I didn't have much time. But, this forced me to really get to the point. I also managed to do a live demonstration of my Q sort tool, so I think everyone got a good overview. Attendance was very minimal and in hindsight I think I should have come up with a sexier title. However, people seemed very intrigued by the technique and had many interesting suggestions and ideas on how to use it. One suggestion was to try a Q sort within the context of faculty teaching evaluations to help identify teaching strengths and weaknesses.

Getting Ready for Next Year


I will make the CHEP conference a priority in my yearly conference planning. Next year's conference dates are February 15-17, 2017. I'll be encouraging everyone to check it out, particularly doctoral students because of its friendly and supportive environment. Proposals are usually due around mid-September. The attendance was about 1,000 people this year, which is about the maximum that the conference venue can accommodate. There was some talk about perhaps having to limit registrations, so be sure to register early!

Friday, January 15, 2016

Creating a Software Licensing Solution with LiveCode

The final development stage of my video analysis tool is coming along nicely. I hope to wrap it up in the next few days in order to do some final beta testing before I release version 1.0 as a commercial product. I keep joking that I plan to price it at the cost of a breve expresso, but I think that is about the right price. I actually plan to give it away to a lot of colleagues and their students, especially here at UGA. (Disclaimer: I was not paid or compensated in any way by the University of Georgia to create this tool.) But, I do think there will be a small market for this tool and I'm looking forward to the entrepreneurial experience that awaits. Just going through all of the steps to get this thing to market and figuring out how to accept payment and provide customer service will be a great learning experience for me. (I considering submitting to one of the available online stores, such as the Mac App Store.)

These thoughts point to the need to produce a free version of the tool that prospective customers can access to evaluate to make sure it serves their needs well. If it is a good tool for them, then I hope it will persuade them to purchase the full version. Likewise, I would like an easy way to give the tool to colleagues for use in their classes. Now, I could produce several different, standalone versions of the tool where each serves a distinct purpose. But, that would be complicated and a lot of work. So, I've come up with a solution that allows me to create and maintain one product that serves all purposes. Now, I'm sure there is a great literature out there somewhere that would explain various approaches or algorithms for doing this. But, true to my design spirit, I just forged ahead and invented my own approach.

Lloyd's Licensing Approach


The approach I used relies on one new global variable that I titled "varFullVersion" that is either true or false. When true - as the name suggests - all options and functions are available to the user. When false, a few critical options or functions are turned off. I have set it to false by default, so the free version is triggered upon start up unless the program finds a certain value in a certain file stored on the user's computer.

Deciding on which options or functions to turn off was an interesting design decision. There is a balance to be struck between giving users enough functionality to be able to evaluate the tool, but not enough to keep them from wanting to purchase the full tool if they find it useful. I settled on disabling two main functions. First, the free version only allows the user to work on one project. If you want to work on another, you have to first delete that project before beginning another. I also removed the capability to export source files. Not doing so would have created a loop hole allowing people to use the free version - albeit inconveniently - pretty much as the full version. They could begin a project, then export the source file and delete the project, only to import the source file later to continue working on the original project. I should probably turn off other functions as well (e.g. ability to import source files), but I'd rather error now on the side of giving people a good opportunity to check out the tool.

How to Integrate Licensing Codes


The next obvious question is how to toggle the varFullVersion variable to true or false. The concept is simple - people download the free version, so the default value is false. Then, if they decide to purchase the full version (or if I want to give to them), I need to give them some code that "turns on" the full version. If you have ever downloaded trial versions of commercial software, you know just how common this is. You download the trial version and if you then purchase the software, you are simply sent a code to unlock it.

One way to do this would be to hard code into the standalone alone a secret code that, if entered by the user, would unlock the full version. But, I wanted to have a little more control than that. I wanted to have a list of codes that I could give out and manage. For example, say I have a colleague who is teaching a course and wants to start using the tool next week with his students. I wanted a way to give that colleague a unique code to share with his students that would be "active" for a short period of time, just long enough for his students to download the tool and activate it. But, I didn't want his students to give out the code to friends and family to activate the tool later. I needed a way to activate or deactivate a list of unique codes at will.

Storing Codes on the Internet


Fortunately, in some of my other LiveCode projects, I have learned how easy it is to use information from text files stored on the Internet. I really like this approach because it saves me from the hassle of creating a database backend for storing simple information. So, I have hard coded into my tool a web address that points to a simple text file containing a list of codes. (Sorry, I won't be giving out that URL here - that would defeat the "secrecy" needed for the approach!) Here is an example of what the file looks like:

 87-93-87-22-44, the current commercial license code  
 bob7395, special code for Dr. Bob to use the tool with his class  
 stop, psych101vat, special code for the introductory psychology courses  
 vatforfamily, a special code just for sharing the tool with family and friends  

Each line has a list of items separated by a comma. The first item is the code. All other items are ignored. Notice that the code in line 3 is "stop." I've simply programmed the tool to ignore the word "stop" as a code. So, if I want to turn off a certain code for awhile, I simply add this word as the first item in that line. If I want to reactivate the code, I remove it. I can also simply substitute a new code for that group at any time. The program reads in all of the lines and will allow any active code to unlock the full version of the tool.

I should mention that I did program in a "back door" code directly into the program. So, if I ever need to unlock the tool for whatever reason (e.g. the Internet is down), I can do so.

How to Save the Codes


As I mentioned, I have the variable "varFullVersion" set to false as its default when the video analysis tool is launched. Obviously, the first things the program does is check to see if the person has previously unlocked the full version. How is this done? In short, I save a secret code stored in a file I won't name on the person's computer. It works kinda like a cookie. Most commercial software program access a special "preferences" folder on the user's computer to store these sorts of files. Maybe I do too, or maybe I don't - I'm not giving out those details here. The idea is simple though, if this secret file and code are found, then varFullVersion is immediately set to true within the first second after launch. Otherwise, the value remains false the free version is provided.

An advantage of using this approach is that if the user gives a friend a copy of the tool after they unlock the full version, they won't know anything about this stored file. So, when the friend launches the program, the free version is triggered.

Final Thoughts


Is this the best way to build a licensing function into a software program? I really don't know, but I doubt it. I'm actually quite sure there are way more sophisticated ways of doing this. But, with a zero budget, this approach seems to work based on my current knowledge of LiveCode. Of course, if my video analysis tool sells a million units, I may hire a real programmer to improve on this design.



Saturday, January 2, 2016

Back to Work on Lloyd's Video Analysis Tool With a Focus on Graphic Design

It's been just over a year since I last wrote about my video analysis tool. I've spent the year in beta test mode showing the app to various groups and giving the app away to anyone who had an interest in using it. My only condition was that they would give me feedback. As of today, a total of 54 people have signed up to be "official" beta testers. (If you would like to be one, just go to my video analysis tool's website and click on the link at the top of the page.) The feedback I've received has generally been very positive with most of the criticisms and suggestions for improvements stemming from the Windows version of the tool (more about that later.)

I've also spent the year using my video analysis tool. I have found it most useful for creating transcriptions of the videos I create for teaching. In fact, I'm seriously thinking of creating a standalone app just for the transcription tool itself.

I'm convinced that my video analysis tool is worthy of greater things, so I've begun a serious effort on producing a significant update. I'm beginning with a focus on improving the tool's graphic design.

If you are one of the four people who read this blog, then you know that I've been very honest about my lack of graphic design ability. You also know that I never let it bother me, nor do I let it get in the way of my prototyping. But, every now and then I get some friendly feedback from people who really do find my stuff to be ugly. I usually just smile and remind them "it's only a prototype." This is a sincere answer because I rarely spend any serious time on graphic design. My goal is on creative ideation to build a working prototype of an original design. However, I have a few colleagues around the country with a refined sense of graphic design who are on the record saying that they simply won't use an app or web site that they find visually offensive. If I'm in the audience, I always get the sense that they then look at me from the corner of their eye.

The bottom-line is that I know I have to improve the graphic design of my video analysis tool if I want people to consider using it and (gasp!) consider paying a small amount to purchase it. (Yes I'm thinking of selling it, but with a price about equal to the cost of a breve expresso at Starbuck's.) Given my budget of zero dollars, I can't hire someone to do this work and I don't have the heart to ask some of the talented graphic designers I know to do it for free. Plus, I really wanted the challenge.

Here is my targeted benchmark for success: No one finds the app visually offensive.

It's not that I don't know anything about graphic design. Heck, in my "classic" (i.e. old) book Computers, Graphics, and Learning (1994), I even wrote about graphic design (p. 195-196):
... there are some generally accepted issues and concepts related to visual layout that are relevant at this point. Even the most specific design principles can be traced to one of four broad categories of visual design and layout: simplicity, unity, emphasis, and balance. In a sense, these principles aptly summarize much of the previous discussion of frame and procedural protocol. All four categories can be supported and described on the basis of human perception and information processing. For example, visual layout should take into account a person's abilities and limitations in selectively perceiving the most important information in a given display. All information coming from the environment will be competing for a person's limited attention. Therefore, a display should be designed to maximize the chances that a person will notice the most relevant quickly; it should also be able to sustain user attention over a period of time. When combined with rapid prototyping procedures and a lifelong hobby of "software watching," these principles can help guide beginners in designing effective screens.
The principles of simplicity, unity, emphasis, and balance are a good guide, though if you don't have any talent (like me), then you can only expect so much. A very weak area for me is color. I tend to use color in the most simplistic ways and I rarely use anything but pure saturated colors. I usually start with the colors of nature (e.g. green, yellow, and brown, with dashes of red), though when I'm knee deep into prototyping I usually just choose almost any new color when another one is needed. As I prepared to improve the graphic design of my video analysis tool, I knew I had to do more than just "try harder." And, it's not that I don't appreciate good graphic design - I think I "know it when I see it."

Before I share my strategy, let me show you the current draft of my tool's two main screens - the title screen and the video analysis screen (click on either to see them actual size).

Video Analysis Tool Title and Analysis Screens: 



For comparison, here are the previous versions: 



Lloyd's Guide to Graphic Design for Those with Little or No Talent


OK, I'm not saying my current design will win any awards, but I hope we can all agree that the changes mark a dramatic and certain improvement. To do this, I followed a simple strategy that I think others also without graphic design talent may find useful.

Step 1: Do a Google Search


I know, genius. It turns out there are lots of talented graphic designers out there willing to share their expertise with you. My starting point was finding a suitable color palette. I did a search using phrases such as "examples of color palettes" and found some very good advice. Here are the two sites that probably gave me the best information and inspiration:

Step 2: Choose the Mood You Want to Project


On some past projects where I've been fortunate to have a professional graphic designer on board, they would typically ask about what mood or first impression is desired for the project. I think this is a good place to start thinking about graphic design. I think in my case I wanted something that felt "professional and productive, yet enjoyable." I didn't want "cutesy," "toyish," or "cartoonish." 

Related to mood is the choice of an organizing framework, which often times equates to using a metaphor. For example, at one point months ago I toyed with the idea of using a medical metaphor for the project - you as a doctor "diagnosing" your video. Another was "video detective" where you are "sleuthing" the meaning of a video. If I had made a choice such as these, then this would have pointed to the use of graphical objects such as stethoscopes or microscopes, a magnifying glass, a Sherlock Holmes pipe, and the like. I obviously decided not to use any overt metaphor for this project, but you get the idea of how it would influence the graphic design.

Step 3: Choose and Stick to a Color Palette


Once the mood and organizing framework is chosen, the next step is to choose colors and graphical objects to implement it. This is where a talented graphical designer can do magic to draw backgrounds for context, characters, and the like. For the rest of us, we might have to use clip art. Either way, a key place to start is to choose and stick to a color palette.

The great thing about the sites above is that they give the color palette for each design in hex notation. This allows me to match the colors exactly. Here were the two examples that really caught my eye:


I've not included a screenshot of either here given that I think this would be a copyright infringement, but you can click on the links yourself to see them. If you do, I'm sure you will see how my title screen was inspired particularly by "Pixels & Aromates." I thought the gradients of brown were warm and friendly. And, for some reason, they evoked a pleasant look of a chocolate milkshake. (Way back when I was trying to come up with a name for this app, I had toyed with the idea of "video milkshake" for reasons I don't remember.) I also really liked the red hue that was used. I decided on using that red for oversized buttons, which may have been too much red. But the color combinations are pleasing to my eye. I made these buttons round to get away from the original boxish look. I also decided that the option to import a source file did not deserve equal prominence, so I de-emphasized that button.

I needed more colors for the analysis screen, so I again consulted the above web sites for guidance. For example, I wanted to call special attention to the video clip controls in the upper right-hand portion of the screen. I settled on two shades of muted orange.

On the analysis screen I wanted to set apart the two save buttons and the one delete button. I used the time-honored (and probably western) tradition of green means "go" or "safe" and red means "stop" or "caution." I also physically separated these buttons to prevent any accidental clicking. (However, I am careful in my user interface design to give adequate warning should an inadvertent click occur.)

One last detail worth mentioning is my use of the golden ratio on the title screen for placing the slightly darker brown band at the top. The band itself divides the large space nicely and the golden ratio (total height divided by height of bottom portion of the screen) of 1.161803 determined how thick to make it.

Step 4: Use the Principles of Simplicity, Unity, Emphasis, and Balance to Create the Screen Design


Probably the biggest change I made was to create a toolbar at the top of the analysis screen using the darkest shade of brown to group navigational buttons and other options. Previously, I had all of these buttons scattered around the screen. The haphazard way these were initially placed mirrored when I created these various options as the prototype of the app was built. I feel this toolbar organizes all of these options very effectively. The other advantage of the toolbar is that I was able to reclaim a lot of screen space. I can now fit a total of 40 tags in the "Quick Tags" window, instead of 24.

I also visually grouped the four main parts of the analysis screen to achieve unity. As you can see from my before and after examples, I really did not make any major changes to the placement of these four areas. But, I made some small, but important design updates. First, I used shades of brown with a thin black border to define each group area. LiveCode has some built in graphic effects, such as drop shadow. I like how this gives the screen some depth. I also made sure everything lined up well for a sense of balance.

As already mentioned, the use of greens, reds, and orange also provide effective emphasis of key areas and functions.

Other Useful Tools


Although you can script colors into LiveCode objects using either hexidecimal or RGB notation, it appears you can only use RGB to "hard code" colors in the inspector window. So, I used this handy Hex-to-RGB converter:

http://hex.colorrrs.com/

My photoshop skills are also minimal, so I didn't want to spend time creating my own buttons. Instead, I used this web site to create prefabricated buttons:

http://dabuttonfactory.com/

I did use photoshop to create the stylized text on my home screen, but here is also a web site I found as a fall-back tool:

http://cooltext.com/

Although I chose orange and green hues that were part of existing palettes shown in the above web site examples, there are also lots of color picker tools out there to help when choosing new colors, such as the following:

http://www.w3schools.com/colors/colors_picker.asp

Note about the Windows Version


I mentioned at start of this blog post that most of the negative feedback from my beta tesers has come from the Windows version of my video analysis tool. Although it's great that LiveCode allows for exporting desktop apps to Macintosh, Windows, and Linux, this really is designed as a Macintosh app. Because this app involves video, a Windows user must have QuickTime installed on their computers. Even then, there are problems that have been reported that are simply a mystery to me. I have simply not been able to sufficiently troubleshoot problems on the Windows side. So, I'm seriously thinking of removing the Windows option, at least until I finish with the Macintosh version.

Final Thoughts


I'm very happy with these graphic design improvements, even though I know I'll continue to tweak the design over the coming weeks. I also enjoyed the process, as time-consuming as it was. If I had the money, I would have much preferred turning this task over to a professional graphic designer. But, maybe this shows that even someone with very limited ability can follow a graphic design process to at least meet the criteria of not making people nauseous when they look at an app.

Of course, if there are any talented graphic designers out there who want to redesign my app for just the fun of it, please drop me a line.