Friday, August 4, 2023

Privacy Policy - 24 Challenge

Privacy policy

We respect your privacy and are committed to protecting it through our compliance with this privacy policy (“Policy”). This Policy describes the types of information we may collect from you or that you may provide (“Personal Information”) in the “Twentyfour Challenge” mobile application (“Mobile Application” or “Service”) and any of its related products and services (collectively, “Services”), and our practices for collecting, using, maintaining, protecting, and disclosing that Personal Information. It also describes the choices available to you regarding our use of your Personal Information and how you can access and update it.

This Policy is a legally binding agreement between you (“User”, “you” or “your”) and primesRus LLC (“primesRus LLC”, “we”, “us” or “our”). If you are entering into this Policy on behalf of a business or other legal entity, you represent that you have the authority to bind such entity to this Policy, in which case the terms “User”, “you” or “your” shall refer to such entity. If you do not have such authority, or if you do not agree with the terms of this Policy, you must not accept this Policy and may not access and use the Mobile Application and Services. By accessing and using the Mobile Application and Services, you acknowledge that you have read, understood, and agree to be bound by the terms of this Policy. This Policy does not apply to the practices of companies that we do not own or control, or to individuals that we do not employ or manage.

Collection of information

Our top priority is customer data security and, as such, we exercise the no logs policy. We may process only minimal user data, only as much as it is absolutely necessary to maintain the Mobile Application and Services. Information collected automatically is used only to identify potential cases of abuse and establish statistical information regarding the usage of the Mobile Application and Services. This statistical information is not otherwise aggregated in such a way that would identify any particular user of the system.

Privacy of children

We do not knowingly collect any Personal Information from children under the age of 18. If you are under the age of 18, please do not submit any Personal Information through the Mobile Application and Services. If you have reason to believe that a child under the age of 18 has provided Personal Information to us through the Mobile Application and Services, please contact us to request that we delete that child’s Personal Information from our Services.

We encourage parents and legal guardians to monitor their children’s Internet usage and to help enforce this Policy by instructing their children never to provide Personal Information through the Mobile Application and Services without their permission. We also ask that all parents and legal guardians overseeing the care of children take the necessary precautions to ensure that their children are instructed to never give out Personal Information when online without their permission.

Use and processing of collected information

We act as a data controller and a data processor when handling Personal Information, unless we have entered into a data processing agreement with you in which case you would be the data controller and we would be the data processor.

Our role may also differ depending on the specific situation involving Personal Information. We act in the capacity of a data controller when we ask you to submit your Personal Information that is necessary to ensure your access and use of the Mobile Application and Services. In such instances, we are a data controller because we determine the purposes and means of the processing of Personal Information.

We act in the capacity of a data processor in situations when you submit Personal Information through the Mobile Application and Services. We do not own, control, or make decisions about the submitted Personal Information, and such Personal Information is processed only in accordance with your instructions. In such instances, the User providing Personal Information acts as a data controller.

In order to make the Mobile Application and Services available to you, or to meet a legal obligation, we may need to collect and use certain Personal Information. If you do not provide the information that we request, we may not be able to provide you with the requested products or services. Any of the information we collect from you may be used to help us run and operate the Mobile Application and Services.

Processing your Personal Information depends on how you interact with the Mobile Application and Services, where you are located in the world and if one of the following applies: (i) you have given your consent for one or more specific purposes; (ii) provision of information is necessary for the performance of this Policy with you and/or for any pre-contractual obligations thereof; (iii) processing is necessary for compliance with a legal obligation to which you are subject; (iv) processing is related to a task that is carried out in the public interest or in the exercise of official authority vested in us; (v) processing is necessary for the purposes of the legitimate interests pursued by us or by a third party.

Note that under some legislations we may be allowed to process information until you object to such processing by opting out, without having to rely on consent or any other of the legal bases. In any case, we will be happy to clarify the specific legal basis that applies to the processing, and in particular whether the provision of Personal Information is a statutory or contractual requirement, or a requirement necessary to enter into a contract.

Disclosure of information

To maintain the highest level of privacy and to protect your Personal Information to the full extent, we do not share your Personal Information with anyone and for any reason.

Retention of information

We will retain and use your Personal Information for the period necessary to comply with our legal obligations, to enforce our Policy, resolve disputes, and unless a longer retention period is required or permitted by law.

We may use any aggregated data derived from or incorporating your Personal Information after you update or delete it, but not in a manner that would identify you personally. Once the retention period expires, Personal Information shall be deleted. Therefore, the right to access, the right to erasure, the right to rectification, and the right to data portability cannot be enforced after the expiration of the retention period.

The Mobile Application and Services contain links to other resources that are not owned or controlled by us. Please be aware that we are not responsible for the privacy practices of such other resources or third parties. We encourage you to be aware when you leave the Mobile Application and Services and to read the privacy statements of each and every resource that may collect Personal Information.

Information security

No data transmission over the Internet or wireless network can be guaranteed. Therefore, while we strive to protect your Personal Information, you acknowledge that (i) there are security and privacy limitations of the Internet which are beyond our control; (ii) the security, integrity, and privacy of any and all information and data exchanged between you and the Mobile Application and Services cannot be guaranteed; and (iii) any such information and data may be viewed or tampered with in transit by a third party, despite best efforts.

Data breach

In the event we become aware that the security of the Mobile Application and Services has been compromised or Users’ Personal Information has been disclosed to unrelated third parties as a result of external activity, including, but not limited to, security attacks or fraud, we reserve the right to take reasonably appropriate measures, including, but not limited to, investigation and reporting, as well as notification to and cooperation with law enforcement authorities. In the event of a data breach, we will make reasonable efforts to notify affected individuals if we believe that there is a reasonable risk of harm to the User as a result of the breach or if notice is otherwise required by law. When we do, we will send you an email.

Changes and amendments

We reserve the right to modify this Policy or its terms related to the Mobile Application and Services at any time at our discretion. When we do, we will revise the updated date at the bottom of this page. We may also provide notice to you in other ways at our discretion, such as through the contact information you have provided.

An updated version of this Policy will be effective immediately upon the posting of the revised Policy unless otherwise specified. Your continued use of the Mobile Application and Services after the effective date of the revised Policy (or such other act specified at that time) will constitute your consent to those changes. However, we will not, without your consent, use your Personal Information in a manner materially different than what was stated at the time your Personal Information was collected.

Acceptance of this policy

You acknowledge that you have read this Policy and agree to all its terms and conditions. By accessing and using the Mobile Application and Services and submitting your information you agree to be bound by this Policy. If you do not agree to abide by the terms of this Policy, you are not authorized to access or use the Mobile Application and Services. This privacy policy was created with the help of WebsitePolicies.

Contacting us

If you have any questions, concerns, or complaints regarding this Policy, the information we hold about you, or if you wish to exercise your rights, we encourage you to contact us using the details below:

rrodini@hotmail.com

We will attempt to resolve complaints and disputes and make every reasonable effort to honor your wish to exercise your rights as quickly as possible and in any event, within the timescales provided by applicable data protection laws.

This document was last updated on August 4, 2023

Made with WebsitePolicies privacy policy generator

Thursday, May 6, 2021

My OCD School Year

This is a true story, but it's never been told.  Wait, I did tell it to a psychiatrist in 1978 when I was in therapy.  The story is that I had Obsessive Compulsive Disorder during eighth grade at Sacred Heart School -- the Catholic grade school I attended in Manoa, PA.

Catholic grade school was a bitch, but when you're in the middle of it you think it's normal.  I remember the fear I developed in first grade. I was terrified of the nuns.  They could do anything to you for the slightest misstep. I was afraid to ask to go to the bathroom during class because they said kid is supposed to "take care of his needs" outside of class time.  Otherwise, you would have scores of little kids abusing bathroom privileges.  Maybe that's why I shit my pants a couple of times during those years.

The situation got really bad in eighth grade.  My all-male class had a young nun teaching us.  Sister Helen was probably the youngest nun at the school and she wore perfume.  Well, maybe not perfume, but strongly scented soap which must have been sanctioned by the Order of Immaculate Heart nuns.  I recall she would swoop down the narrow aisles of desks and you could close your eyes and tell how close she was by the fragrant smell.  It was during Sister Helen's reign of terror that I developed OCD.

OCD has two components.  Obsession with disturbing thoughts coupled with compulsions that serve to relieve those thoughts.  I only remember the compulsions to tell the truth.  Let me tell you about them.

Sister Helen had us dedicate each piece of school work that we did.  The dedication could be a simple cross at the top center of the page.  Or it could be the initials A.M.D.G. (Latin: Ad Majorem Dei Gloriam / English: For the Greater Glory of God).  If you are a true believer, like I was, you could use a combination of the two.

As a good Catholic boy, and a good student, I started dedicating the shit out of my school work.  I would write in ink

on every page.  Then I would see some imperfection, like the M wasn't proper penmanship so I would forcibly erase it and write over it.

Before long each page was both messier due to the erasures, and neater due to the improvements (actually, it was always messier).  Eventually the dedication looked something like this.


Since each assignment had these blotches, Sister Helen noticed.  "Robert, what are you doing?" "Nothing, Sister," I would reply. She would ask again and I couldn't answer because I didn't know why I engaged in this compulsion.

This wasn't my only compulsion.  Before going to bed I would say my nighttime prayers.  In previous years I did this at my bedside, but in eighth grade I started kneeling in a bedroom closet.  I would even kiss the floor as an act of penitence.  My father caught me once and demanded an explanation.  Since I didn't know why I was doing what I was doing, I told him I was just praying.

All of this seemed to me, a 13-year-old kid, like a bearable cross.  Then, one day, I crossed a line (accidentally though).  I had stayed after school to clean the classroom.  One task was to close the windows which protruded outside the building on triangular hinges.  To do this you used a pole and exerted pressure in the top center of the window frame.  When I did this one of the window panes cracked.

Sister Helen was furious.  She thought I had done this on purpose.  She demanded to see my parents! I pleaded that it was an accident, but she wouldn't have it.  The meeting took place without me and I don't know how it transpired.  My father must have sensed that the good sister was causing me great mental stress and probably told her to back off.  He probably paid for the window too.

That was my eighth grade -- the last year before Catholic high school.  Surprisingly, things got better in high school with male teachers who weren't bent on messing with your mind.  I continued to be an outstanding student and the compulsions just disappeared.

Now the careful reader will ask, "Your compulsions were obvious, but what about the obsessions?"  I don't recall them so much but my therapist (years later) gave an easy explanation.  His view was that I was entering puberty and must have been having sexual thoughts and urges.  Sister Helen was probably at the center of a forbidden fruit scenario.  "Makes sense," I remember saying.

Does telling this story help anyone?  I don't know.  It wasn't cathartic for me, and it probably just amused you.  But I can look back on my 13-year-old self and say, "Hey, kid, you survived eighth grade."  And I'll take that as a compliment.


Wednesday, April 26, 2017

Rocky and his friends

Many years after our first meetings, I met two old friends - Walking Man and Mr. Natural.  My first encounter with these two was in the early 1970s while I was an undergrad at Penn. I consider them early philosophy teachers.

Mr. Natural was a Robert Crumb character who frequented his underground comix.  Here is a Wikipedia description of Mr. Natch:
Mr. Natural has strange, magical powers and possesses cosmic insight; but he is also moody, cynical, self-pitying, and suffers from various strange sexual obsessions.
The comic encounter I most remember is this exchange between Schuman the Human and Mr. Natural.
Schuman:  "Mr. Natural, what does it all mean??"
Mr. Natural: "It don't mean sheeit."
My meeting with Mr. Natural occurred at Penn's Institute of Contemporary Art in 2008.  Boy, he hasn't aged a bit.  Must be his lifestyle.


I encountered Walking Man #1 at the Carnegie Museum in 2016.  This was another 40+ year hiatus. He adorned the cover of William Barrett's Irrational Man, a study in existentialism published in 1958.  According to Barrett modern man has had his morality attenuated to the point where he resembles a sculpture by Giacometti.


I read Barrett's book and lots of other existentialist writers while at Penn.  Why?  For the youthful expansion of religious and mental boundaries.  It was like drinking rock gut whiskey -- if you survived you were a real man.  During that time others were fighting in Vietnam to prove their manhood.  I was content to read Nietzsche.

This leads to how I got the nickname "Rocky."  It has nothing to do with Rocky Balboa (1976) but everything to do with the Beatles' Ballad of Rocky Raccoon (1968).

One afternoon at Penn Jimmy V. walked into my dorm room and found me reading some existentialist.  He immediately started singing, "Rocky Raccoon sat in his room, only to read Friedrich Nietzsche."  The rest is history.



Saturday, May 16, 2015

Life Gets Easy

Said the coal to the diamond, "Why so hard?" Said the diamond to the coal, "Why so soft? Life is hard. Be hard!" (paraphrase of The Hammer Speaks story) -- Nietzsche.












Recently life, my life, has gotten easy, not hard.  Let me explain.

For the last three years I have participated in the local Y's sprint triathlon.  "Sprint" means "short," but still 1.5 to 1.75 hours of intense aerobic exercise is pain-inducing.  One of my motivations for doing this was to see how I compare to my peers, and I learned not too well.  Here are my peer group results:

  • 2012: 4 of 6
  • 2013: 6 of 7
  • 2014: 9 of 9

I swore that I would not participate this year but they introduced a new event called Aquabike (500 m swim, 20 km bike, no run).  My time was okay -- 1 hour and 16 minutes.  And I won my age bracket (full disclosure: I was the only one in my age bracket).  Life gets easy.

Here's another example.  I always wanted to teach a calculus course.  Why? Because I never really learned calculus (it's a long story) and I know that the best way to learn a subject is to teach it.  Well I do teach MAT135 Business Pre-calculus and maybe someday the school will schedule me to teach MAT136 Business Calculus.  In any case, these courses are not hard.  Life gets easy.

So maybe Nietzsche is wrong.  Life is not hard.  At least not all of the time.


Monday, April 27, 2015

My First Aquabike Event



Did I participate in the UMLY triathlon this year? No,  Did I try the new aquabike (swim + bike) event? Yes.

The swim event was run entirely different from previous years.  Instead of a wave start where about 12 people swim in the pool at one time, followed by another wave, each swimmer was started about one minute apart and you swam a zig-zag pattern across the pool.  It worked!

I was amazed that I even passed someone in the pool.  This only happens when a) the passer is a very fast swimmer or b) the passee lied about her estimated time for swimming 500 meters.  Let's dispel a) right away as I am not a fast swimmer.  The woman I passed must be really slow, but gave a really optimistic time estimate.

The bike route was longer than before and had quite a few new turns to stay on course.  I had practiced the route the week before, however I still managed to miss a turn.  On the return route there was a cop signalling to me to make a left hand turn from Sugartown onto Church Rd.  Due to a brain freeze I zipped right past him following the route from the previous year.  I quickly realized my mistake, braked hard, and circled back.  I even apologized to the cop for my mistake (did I think he was going to give me a ticket?).  Must have added 20 seconds to my overall time.

A final comment on my placement.  First the good news -- I finished first in my age bracket.  Now the bad news -- I was the only one in my age bracket and was last among the six male finishers.   I still had fun (but no photos at all).

Swim (500 m) 15:13
Transition          5:50
Bike (20 km)   55:54
Total             1:16:17

Tuesday, April 7, 2015

My Last Sprint Triathlon (sort of)


You might think I am really getting faster from year to year.  You would be wrong.  On the day of the race I learned that they shortened the bike route due to potholes on one of the major downhills of the course.  Makes sense -- don't want anyone crashing their bike due to a pothole.  Right before my start I overheard someone say that they changed the running route.  Okay, probably just a tweak to the route that's been used since the event was established.

Now as I completed the swim, and finished the bike ride, I started the run which is the most god-awful physical experience one can bear.  Getting off the bike my legs are crampy and I start running with tiny strides because it feels like elastic bands are attached between my legs.  I don't feel like running 5 meters let alone 5 kilometers.  Soon I discover that they completely re-routed the course.  I have no idea how far I've run or how far I still have to go.  I ask a volunteer at a water station and just get a "I don't know."

Okay, I finished but I vowed this was my last sprint triathlon.  Why? Besides hating the run at the end, I hate the training prior to the event.  A heavy training day (even a light training day) leaves me exhausted for the rest of the day.  I also have a light headache which I learned is called an "exercise headache." Only a sick man would do this to himself.

Final note: This posting was written in 2015 almost a full year after the event.  I was going to give up this event when the Y announced a couple of variations:
- sprint triathlon (500 m. swim, 10 km. bike, 5 km. run)
- duathlon (5 km. run, 500 m. swim, 5 km. run)
- aquabike (500 m. swim, 20 km. bike)

Now that aquabike event looks interesting...

Thursday, November 21, 2013

How Does Twentyfour Challenge Work?

Download Twentyfour Challenge (it's free) for Android and iOS from these locations:
Google Play
iTunes Store






The Phonegap Diaries describe how the Twentyfour Challenge app was built, but they don't really describe how it works. That's what I'm going to do here.

You probably guessed that the app has a built-in (recursive descent) parser that processes what is in the expression text box on the solver screen.
Within the app the text box does not permit data entry. If it did the user could just type in the goal number (say 24) and would immediately be rewarded with solving the problem. While parsing the code, it also builds an expression tree reflecting operator precedence for this ANTLR grammar (ANTLR is not used within the app):

grammar twentyfour;
solution:	expr ;
expr	:	multExpr ('+' multExpr | '-' multExpr)*
	;
multExpr:	atom ('*' atom | '/' atom)*
	;
atom	:	RATIONAL
	|	'(' expr ')'
	;
RATIONAL:	'0'..'9'+ ('/' '0'..'9')+;

The parser and rational expression evaluator are at the heart of the application, but where do the problems come from? The problems (and there are hundreds of them) are pre-programmed within the application. Each has this form:

// lvl :goal:   tuple1   :   tuple2   :     solution
    "4 : 24 : 6,10,15,6  : 2,10,15,10 : ((15-10)*6)-6"

A valid problem must have these properties:
  1. One of the tuples must yield a solution whereas the other must not
  2. The correct tuple values must appear in the solution expression.
  3. The solution expression must evaluate to the goal
Note that there may be more than one valid solution expression using the correct tuple. This just reflects the fact that 4 = 2+2 and 4 = 2*2. Only one of these valid solutions is pre-programmed, but the user can enter either solution to get the correct answer.

This brings up the subject of hints. I tried lots of alternative versions of the 24 game from the iTunes store. Most use four operands and some of the problems would stump me for minutes on end. All of the programs have a timer which makes you nervous as the seconds keep ticking away. If only the app would give me a hint!

That's it! in the next version of Twentyfour Challenge I will make the app both harder and easier. I will implement a level 4 of difficulty (that is, four operands) and I will implement a hint function at all levels of difficulty.

So how do hints work? There are two contexts -- the problem screen (below) and the solver screen.


Here the hint has been given as the incorrect tuple is disabled. The user should click the active tuple and move to the solver screen.

On the solver screen the hint button progressively shows the solution to the problem in the hint area (below).

Is this the best design for hints? Maybe not, but it certainly was easy to implement using regular expressions. The program examines the canned solution and extracts the operands from it. Here's the regular expression used to extract integer operands:

game.hintNumbers = game.problemSolution.match(/(\d+)/g);
game.hintSolution = game.problemSolution.replace(operand, "?");

When hints are given it just substitutes these numbers back one by one.

At first I though the hints should build on the progress the user has made on her own. It would suggest the next operator or operand (or clear a bad operator/operand). This was very hard to implement. Keep it simple, Sam!

Finally I should mention a back office application I wrote (thankfully) in Java that generated level 3 (three operands) and level 4 (four operands) problems. I had to write this program to guarantee that the pair of tuples for level 4 problems had the desired property of one correct and one incorrect tuple (the incorrectness had to be guaranteed).

This was done by brute force computation. The program generates four random integers and then all possible expressions using them as operands. It then evaluates each expression tree and records the results. Here's some output from the program:

	"4 : 24 : 8,11,15,9 : 6,9,18,8 : ((9-8)*18)+6",
//                                6-((8-9)*18)
//                                ((9/18)*8)*6
//                                6/((18/9)/8)
//                                ((6/18)*8)*9
//                                9/((18/6)/8)
//                                ((9-8)*6)+18
//                                18-((8-9)*6)
//                                ((6*9)*8)/18
//                                ((6*9)/18)*8
//                                8/((18/6)/9)
//                                (6*9)*(8/18)
//                                (6*9)/(18/8)
//                                (6/18)*(9*8)
//                                (9*8)/(18/6)
//                                (6+18)*(9-8)
//                                (6+18)/(9-8)
//                                (6*8)*(9/18)
//                                (6*8)/(18/9)
//                                (9/18)*(6*8)
//                                (6*8)/(18/9)
//                                (9-8)*(6+18)
//                                (6+18)/(9-8)
//                                (9*8)*(6/18)
//                                (9*8)/(18/6)
//                                (8/18)*(6*9)
//                                (6*9)/(18/8)

Obviously this problem has tons of solutions, but there is no solution involving [8,11,15,9].

Friday, October 11, 2013

Phonegap Diaries: Summary

Here's a bullet point summary of my lessons learned.

Bright Spots

  • Phonegap lives up to its promise
  • JQuery Mobile also lives up to its promise.  It game me a better UI and excellent portability
  • Translation from Java to Javascript is not too difficult.
  • There exist real unit testing tools for Javascript

Disappointments

  • <audio> tag and its API had spotty implementation (not working on iPad2 and Galaxy devices).  Why it works on some devices (iPhone4 w. iOS6) is beyond me.
  • JQM documentation needs significant improvement
  • Apple process for releasing to iTunes store is both lengthy and bizarre
  • Lost all i18n capabilities using HTML5 / javascript

Gotchas

  • iOS upgrade on a device is irreversible
  • stackoverflow.com is good source of info but can mess you up:
    •             right answer to a different problem
    •             right answer for a specific version of JQM (or phonegap, or css, ...)
  • javascript type system is tricky.  
    • For example $mobile.changePage("problem_screen?newProblem=false") cases a transition to the problem screen.  The parameter passed is 'false'.  But 'false' evaluates to true.  Huh? 'false' is a string that needs to be converted to Boolean false.

Unsolved problems

  • Can all information for platform generation emanate from "config.xml?"
  • What is the best way to detect and report javascript errors?
  • What can be done to speed up application load time (5-8 seconds)?

Plans for the Future

I plan future versions of Twentyfour Challenge that include these features:
  • a new level using four numbers
  • a "give me a hint" function during game play
And I'm waiting for feedback from a couple of middle school math teachers whom I know.

Phonegap Diaries: Process

Introduction

This article discusses the process used to develop Twentyfour Challenge.  First you have to understand the project structure.

Project Structure

Below is the file structure for Twentyfour Challenge as a PhoneGap project:

phonegap-projects
|____.DS_Store
|____Twentyfour                 <= PhoneGap project root
| |____.cordova
| |____.svn
| |____merges
| |____platforms
| | |____android                <= imported into Eclipse/Android
| | | |____AndroidManifest.xml
| | | |____ant.properties
| | | |____assets
| | | | |____www
| | |____ios
| | | |____build
| | | | |____Twentyfour.app
| | | | | |____www
| | | |____ Twentyfour.xcodeproj    <= imported into XCode
| |____plugins
| |____www              <= source code here! Dreamweaver site root
| | |____config.xml
| | |____css
| | | |____index.css
| | |____img
| | | |____logo.png
| | |____index.html                 <= main page
| | |____js
| | | |____index.js    
| | |____res
| | |____spec
| | |____spec.html

Most of my work is under that www folder and this is what really needs to be under source control.  There are platform specific changes that need to be made under android and ios folders also.

Development Process

After some fits and starts I got into this basic cycle:
  1. Write new html and/or javascript within DW
  2. From DW launch Chrome on index.html page
  3. Set breakpoints on pageinit events within application
  4. Execute application looking for errors/exceptions/bugs
  5. Fix errors/exceptions/bugs in DW
  6. Repeat

Simulator Testing

Periodically I would test the application in either an AVD (Android Virtual Device) or the iOS simulator.  Cordova CLI made this incredibly easy to do:

cordova build ios
cordova emulate ios

The last command will launch the ios simulator and give you a feedback on the look and feel and basic functionality.  But it gives you no information about what's going on within the application.  So you must use XCODE (Eclipse for Android) and launch the simulator (AVD for Android) from there.  This will show any errors that ios detects so you can correct them.

Device Testing

At some stage you have to start testing on a physical device.  You will need to use Eclipse with the ADT to run your app on an Android device, or XCODE to run it on an ios device.

On Android I only tested on my current smartphone – a Samsung Galaxy Stellar model.  On ios I tested on an iPad2 and several iPhone4s.

Icons

Don’t forget those icons!  Whereas there are a reasonably small number of icons to develop for Android there are an unreasonably large number of icons to develop for ios.

Don’t forget the all of those screenshots and splash screens that you have to provide.

Summary

The process I describe should include all of the rabbit holes that I went down trying to find solutions to my problems; however, I choose not to mention them.  Google (and stackoverflow) should be mentioned as primary development tools as these were the only means for getting unstuck when I was stuck.

Other postings:




Phonegap Diaries: Technologies

Introduction

Here I’m going to review the programming technologies used in the Twentyfour Challenge.  These include:
  •         Html5
  •          CSS3
  •          Javascript
  •          JQuery Mobile
  •          PhoneGap

Html5

There’s not too much to say about Html5 as I only used a couple of features that are specific to it:  local storage and the <audio> tag.  I also used a specific tag that is crucial to all PhoneGap projects.
Local storage is incredibly easy to use.  I use it to store the game options for Twentyfour and to keep track of the high scores.  The code below saves the game options:

function storeOptions () {
 // must use JSON stringify here!
 localStorage["tfc.options"] = JSON.stringify(options);
}

Here’s the code that reads the stored options:

function loadOptions () {     
 // are options in localStorage?
 if (localStorage["tfc.options"]) {
  options = JSON.parse(localStorage["tfc.options"]);
  // Options that are not strings need to be converted
  options.difficulty = Number(options.difficulty);
  options.count      = Number(options.count);      
  options.soundEnabled = Number(options.soundEnabled);
 }
 game.numSystem = options.numSystem;
 game.difficultyLevel = options.difficulty;
 game.countProblems = options.count;
 game.soundEnabled = options.soundEnabled;
};

The tag is complemented by a simple DOM-oriented API to play the sound file that is referenced.  It is also very easy to use.  The sound file (applause) worked in the Chrome browser, the iOS simulator, and an iPhone 4 device running iOS6.  It did not work in my own Android device (Samsung Galaxy Stellar I200), my iPad2, and another iPhone4 running iOS7.  I know I did everything right so I decided not to advertise the applause function.

A crucial <meta> tag needed by PhoneGap (really just the html5 compliant browser) is:
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, maximum-scale=1" >

There are many stackoverflow questions regarding the application’s web page being shown in a teensy-weensy font.  The solution is to add the above meta tag.

There’s one more thing that almost drove me crazy regarding a brower-based application – the back button.  The application runs as a “WebView” (Android terminology) where the browser does not display any “chrome”  (not Google Chrome, this is chrome like the back button, forward button, refresh, etc.).  This works fine on iOS but on Android there is a hardware back button.

I found that while playing a game of Twentyfour you must not use the back button at all as it destroys the state tracking that the app must perform.  I will discuss the solution later in this article.

CSS3

Most of the styling for Twentyfour comes from JQuery Mobile.  My hat is off to the professionals that developed CSS/html code that is portable across Safari, Chrome, and Internet Explorer, especially since the vendors of these browsers compete against one another.

I did, however, have to define a few styles for specific situations.  Here’s the problem “goal” which is really a button with some style changes.


The style changes are:

.goal-style   {
  text-align: center;
  background: chartreuse;
  ui-disabled: true;
}

 The trick to achieving this style is to add it dynamically when the page is rendered.  

            $('#problem-goal').addClass('goal-style');

The most important reason for learning CSS is due to the fact that JQuery uses its notion of a selector extensively.

Javascript

Ah, Javascript, how do I hate thee?  I speak these words as a Java programmer who trusts the statically typed language completely.  Remember that Twentyfour started as a native Android application that at its heart contained six classes with 775 lines of code (carriage returns counted here).  This includes a simple algebraic expression parser and evaluator.

Since I was skeptical of translating my Java code to Javascript by hand, I first sought an automated solution in the Google Web Toolkit (GWT).  Google created the GWT so they could create sophisticated browser-based applications (think Google Maps) in Java and then convert the client part to html/javascript.  I did get my 775 lines of java code translated by GWT, but then realized that there was no way to incorporate the generated javascript into a PhoneGap application.

So I hand translated to Javascript using techniques documented by David Flanagan in “Javascript: The Definitive Guide.”  It resulted in six classes and 588 lines of code.

Yes, there were type conversion surprises during development, but thorough testing flushed them out.  I developed unit test cases for the important code and gained the desired degree of confidence in the reincarnated algebraic expression parser and evaluator.

On every page of the application I included all of the Javascript files of the application (including JQuery Mobile files).  This was recommended in various books and Internet articles that I read.  It also benefits the use of a Javascript debugger.  Chrome, for example, will not allow you to set breakpoints on a page if it doesn’t see Javascript included on the page.

There are a couple of takeaways from this:
  1.        You must order your Javascript includes avoiding forward references.
  2.        You have to live with an enormous number of global variables.

JQuery Mobile

The technology I had the most difficulty with was JQuery Mobile (JQM).  The technology (including JQuery itself) has been going through many rapid revisions.  And there is the fundamental fact that JQM loads a document into the browser’s DOM and manipulates that one DOM thereafter.  This means that you get one chance to set up your event handlers.

Let me backtrack and try to re-express myself.  For the longest time I could not get my JQM page events to fire properly.  My stackoverflow searches resulted in conflicting information:  “use ‘bind’ on the pageinit event.”  “No use ‘on’ event.”  “Sorry you’re both wrong use ‘delegate’.”  No matter what I tried the JQM event never fired off my handler code.

Then I realized that the DOM is created exactly once by JQM and just updated when new pages are loaded via AJAX (really HJAX here).  The “binding” code that worked for me is shown below.

$(document).delegate('#index', 'pageinit', function() {
  console.log('#index: pageinit');
  // local event handlers
  $('#play').on('click', function() {
    console.log('play clicked');
    startGame();
  });
});

This breakthrough got me off the dime so I could learn the JQM widgets and events.  The most confusing event is one of the most important – the ‘click’ event.  Due to the nature of clicking using a mouse versus tapping on a touch sensitive screen, JQM differentiates separate events: ‘tap,’ ‘click,’ and ‘vclick.’  I started with ‘click’ but found it introduces an annoying 300 ms delay which isn’t good for rapid play.  So I switched to ‘tap’ which has no delay by occasionally has its own unwanted side-effects (ghost clicks).  ‘vclick’ wasn’t any improvement so I left the implementation with ‘tap.’  I finally learned that 'tap' works fine as long as you immediately stopped event propagation.

// event handlers
  
$("#score-ok-btn").tap (function(e) {
  e.preventDefault();
  gamePauseAudio();
  $.mobile.changePage('index.html');
});

Another surprise from JQM is that when you manipulate one of its widgets you must explicitly tell JQM to refresh its display of the widget.

$('#num-probs').val(game.countProblems).slider('refresh');

There were tons of stackoverflow questions asking, “Why doesn’t my updated widget show the update?”  Answer: “you didn’t refresh it.”

PhoneGap

As I mentioned in a previous blog PhoneGap gives you free packaging of your browser application and some level of Javascript access to native device APIs.

I thought I could live without any need for device-specific API but that Android hardware “back” button was a source of much aggravation.  If the user clicked in the middle of a game the entire game state would be invalid and many Javascript errors would occur.

So the back button became my nemesis as it has been forever for web developers.  I thought of several approaches:
  1. Disable the back button
  2. Manipulate the browser’s stack of “back” pages
  3. Catch every page transition and only allow the transitions for a “normal” game
  4. Detect when the hardware back button was pressed
Well #1 is prohibited.  #2 is difficult given the DOM APIs available.  #3 requires a lot of careful programming and is very brittle.  #4 is supported by PhoneGap.  After exploring #1 through #3, I found A PhoneGap API (see the Events API)  that solved the problem completely.  When the hardware back button is pressed on Android (iOS doesn’t have this) then just jump to the application homepage.  Thank you, PhoneGap!

PhoneGap also does the packaging and in this area it encourages you to use Adobe’s PhoneGap build service.  I did not use this approach for a couple of reasons:
  1. It costs money (there is a limited free plan)
  2. You need to package, deploy, and test your app on real devices before a release build.
The build service drives off the application’s config.xml file.  I discovered more documentation on config.xml at Adobe’s build site than I did at W3 Consortium (there’s a minor standard for widget packaging) and at the PhoneGap site.

It is not clear to me if the PhoneGap CLI tools process config.xml the same as the PhoneGap build service.

Summary

There’s a lot of technologies involve here.  JQuery Mobile keeps its promise for great looking portable UIs across mobile clients (Javascript too).  And PhoneGap delivers in its packaging for specific platforms.

Other postings: