Saturday, 10 October 2020

React Native Development Environment Setup

 I choose to setup the react native development environment for iOS first since I already have Xcode installed.

  • React Native CLI (not using Expo since I may need to use native code)
  • React Native with TypeScript

Target OS: iOS

Dependencies:
  • Node : already installed v12.9.0 using nvm v6.14.8
  • Watchman: su admin; brew install watchman
  • Xcode with command line tools : already installed
  • Cocoapods: already installed
Create react native project.
npx react-native init <project> --template react-native-template-typescript

Run Metro
cd ~/<project>; npx react-native start

Run iOS App
cd ~/<project>; npx react-native run-ios

Target OS: Android

Dependencies:
  • brew cask install adoptopenjdk/openjdk/adoptopenjdk8
  • Install Android Studio
    • Android SDK Platform 29
    • Google APIs Intel x86 Atom System Image
    • Android SDK Build-Tools select 29.0.2
  • Add ANDROID_HOME environment variable to .profile and add PATH.
Run Metro
cd ~/<project>; npx react-native start

Run Android App
cd ~/<project>; npx react-native run-android

Wednesday, 1 April 2020

Using GitHub from Xcode and Mac OS Command Prompt

Introduction

I have the front end app developed in Xcode and the backend logic developed in NodeJS.  Therefore I will need to manage 2 independent repositories.

Using GitHub from Xcode 11

If you Xcode project is using local Git, you can create new remote GitHub repository directly in Xcode.  Follow this link.

Using GitHub from Mac OS Command Prompt

You need to create an empty private repository in GitHub manually first followed by pushing it from command prompt.
  1. Create Repository in GitHub manually.  Set it to private.
  2. Copy the clone url.  Example: https://github.com/username/project_name.git
  3. On Mac, open the command prompt and go to the project folder.  Ensure that the git user has permission to the repository.  Check the user using git config user.name
  4. Set the origin URL to the new repository.  git remote set-url origin https://github.com/username/project_name.git
  5. If the local git repository doesn't have any existing remote.  You can use add.  git remote add origin https://github.com/username/project_name.git
  6. Push to remote.  git push -u origin master
  7. Omit the -u parameter for subsequent push.
If you see this error, you can clear your credential first.
$ git push origin master
remote: Repository not found.
fatal: repository 'https://github.com/username/project_name.git/' not found

Tuesday, 12 February 2019

Migrating to ParseServer 3

Introduction

ParseServer 3 comes with a few breaking changes and requires a few type of changes.  I am documenting my experience of migrating my App.  Since we are all coders, I illustrate the code before and after migration in diff output format.

Approach

My current code base do not use backbone style callbacks.  I make extensive use of promises, both sequential and parallel (i.e Parse.Promise.when).  When I do migration, I keep the existing promises and therefore I do not use need to use async function.  These are the main changes:
  • Change Parse.Promise to native Promise
  • Parse.Promise.as to Promise.resolve
  • Parse.Promise.error to Promise.reject
  • Parse.Promise.when to Promise.all
  • Change cloud function
  • response.success("result") to return "result"
  • response.error("problem") to throw new Error("problem")
  • response.error(array) to throw array
  • Remove the redundant error handling block
    }, function(error) {
      response.error(error);
    });

Original

Parse.Cloud.define("getPlayer", function(request, response) {
  var player = request.params.player;

  // get session token for login user.  default to empty for non-login
  var sessionToken = {};
  if (request.user) {
    sessionToken = {sessionToken:request.user.getSessionToken()};
  }

  var p1 = exports.getPlayer(sessionToken, player);

  return p1.then(function(result) {
    response.success(result);
  },
  function(error) {
    response.error(error);
  });
});

exports.getPlayer = function(options, player)
{
  var query = new Parse.Query("Players");
  query.equalTo("name", player);
  return query.find(options);
}

Migrated

Parse.Cloud.define("getPlayer", (request) => {
  var player = request.params.player;

  // get session token for login user.  default to empty for non-login
  var sessionToken = {};
  if (request.user) {
    sessionToken = {sessionToken:request.user.getSessionToken()};
  }

  var p1 = exports.getPlayer(sessionToken, player);

  return p1.then(function(result) {
    return result;
  }); 
});

Diff output

-Parse.Cloud.define("getPlayer", function(request, response) {
+Parse.Cloud.define("getPlayer", (request) => {
   var player = request.params.player;
   // get session token for login user.  default to empty for non-login
@@ -935,37 +919,13 @@ Parse.Cloud.define("getPlayer", function(request, response) {
   var p1 = teamMod.getPlayerTeamElo(sessionToken, player);
   return p1.then(function(result) {  
-    response.success(result);
-  },
-  function(error) {
-    response.error(error);
+    return elo;
   });
 });

Cloud Function

Ordinary Cloud Function

Most of my cloud function are migrated with minor changes.  Example:

-Parse.Cloud.define("getGroup", function(request, response)
+Parse.Cloud.define("getGroup", (request) =>
 {
   if (!userMod.isLogon(request))
   {
-    response.error("Uh oh, you are not allowed to run this.");
-    return;
+    throw new Error("Uh oh, you are not allowed to run this.");
   }

   var sessionToken = userMod.getSessionToken(request);
@@ -1976,23 +1886,22 @@ Parse.Cloud.define("getGroup", function(request, response)
   var p1 = groupMod.getGroup(sessionToken,username);

   return p1.then(function(result) {
-    response.success(result);
-  }, function(error) {
-    response.error(error);
+    return groups;
   }); // p2 = p1.then

 }); // getGroup

Returning Array as Error

If you need to return array of PFObject as error.  You would need to use throw array instead of throw new Error(array).

This is the diff output.
-      response.error(matches);
+      // Note: Use throw array instead of throw new Error(array) to pass
+      //       array of PFObjects to caller.
+      //
+      // Result of throw array is
+      // error: [ ParseObject { _objCount: 6, className: 'Match', id: '12345678' },
+      //  ParseObject { _objCount: 9, className: 'Match', id: '22345678' },
+      //  ParseObject { _objCount: 11, className: 'Match', id: '32345678' },
+      //  ParseObject { _objCount: 13, className: 'Match', id: '4234567' },
+      //  ParseObject { _objCount: 15, className: 'Match', id: '52345678' } ]
+      //
+      // Result of throw new Error(array) is
+      // error: [object Object],[object Object],[object Object],[object Object],[object Object]
+      throw matches;

Triggers

Triggers are function such as beforeSave, afterSave, beforeDelete, afterDelete.  These functions are migrated in similar way as cloud functions.

-Parse.Cloud.beforeSave("Player", function(request, response) {
+Parse.Cloud.beforeSave("Player", (request) => {
   var player = request.object;

   // check if the object isNew (i.e have not been save before)
   // skip if the team record is not new
   if (!player.isNew()) {
     // no need to process and just return
-    response.success();
+    return;
   }

@@ -905,12 +892,13 @@ Parse.Cloud.beforeSave("Player", function(request, response) {

   return p1.then(function(status) {
     if (status && status.length > 0) {
-      response.success();
+      return;
     } else {
-      response.error("Player.beforeSave failed to save Player for " + game + "," + circle + ".");
+      throw new Error("Player.beforeSave failed to save Player for " + game + "," + circle + ".");
     }
   }); // p2 = p1.then

 }); // beforeSave Player

Reference


Wednesday, 6 February 2019

Using Git Worktree, Branch and Merge on Multiple Heroku Environments

Introduction
Git worktree is a handy feature when a developer is working on major upgrade, such as between Swift upgrade or any major version upgrade that are breaking existing API.

Create a Staging Environment on Heroku
If you are hosting your app on Heroku, you can create a staging app using heroku CLI (command line interface).  The following two command create elostaging remote and rename the auto-created app name, salty-garden-12345 to elostaging.
$ heroku create --remote elostaging
$ heroku apps:rename elostaging --app salty-garden-12345

Create a Branch and Worktree
Organise your directory structure
Git stores it depository in local .git folder and therefore it allows you to restructure your working folder easily.  My original working folder is ~/code/elo.  To allow easier organization of main and branches.  I re-structure my app, elo, working folders to the followings structure.
~/code/elo/main
~/code/elo/branch

This can be done via 3 commands.
$ mv ~/code/elo main 
$ mkdir ~/code/elo
$ mv main ~/code/elo/

Create a Branch
$ cd ~/code/elo/main
$ git branch branch-4.0

Create a Worktree for the Branch
$ cd ~/code/elo/main
$ git worktree add ../branch-4.0 branch-4.0

Commit Changes to Branch
$ cd ~/code/elo/main
$ git add file1 file2
$ git commit -a "Updated"

Deploy from a Branch to Heroku Staging
You can deploy from a branch to staging with the following syntax.
$ cd ~/code/elo/branch-4.0
$ git push elostaging branch-4.0:master

Merge a Branch into Master
Suppose you are done with all works in the branch, you can merge the changes back to master using the following commands.  You will need to issue the merge command in the master worktree.

$ cd ~/code/elo/main
$ git merge branch-4.0
Updating xxxxxxa..yyyyyy2
Fast-forward
 file1 |  9 +++++++++
 file2 | 16 ++++++++++++++++
 2 files changed, 29 insertions(+)

Delete Worktree
You can delete a worktree by deleting the folder and run
$ cd ~/code/elo
$ rm -rf branch-4.0
$ cd ~/code/elo/main
$ git worktree prune

Merge Production Fixes in Master to Branch
While you are working on a branch, you also make a hot fix in the master.  You can bring the changes in master back into the branch so that you have less work to merge in the future.

$ cd ~/code/elo/branch-4.0
$ git merge master
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Auto-merging xxx/yyy.js
Auto-merging xxx/zzz.js
Automatic merge failed; fix conflicts and then commit the result.

In this case, merge the conflict in readme.txt manually.  Test and then commit the changes into branch4.0.

git add readme.txt
$ git commit -m "merged production hotfix"

References
These are useful references on worktree, heroku, git branching and merging.
  1. SaltyCrane git-worktree-notes
  2. Useful commands from Matts
  3. Git Branching and Merging Basic
  4. Managing Multiple Environments for Heroku App

Saturday, 22 December 2018

Adeline Note Privacy Policy

We collect personal and activity data, which may be linked.

We use technologies like cookies (small files stored on your browser), web beacons, or unique device identifiers to identify your computer or device so we can deliver a better experience. Our systems also log information like your browser, operating system and IP address.
We also may collect personally identifiable information that you provide to us, such as your name, address, phone number or email address. With your permission, we may also access other personal information on your device, such as your phone book, calendar or messages, in order to provide services to you. If authorized by you, we may also access profile and other information from services like Facebook.
Our systems may associate this personal information with your activities in the course of providing service to you (such as pages you view or things you click on or search for).

We collect or share your location only with permission.

In serving you, we may use or store your precise geographic location, if you give us permission to do so. We do not use or share this data for any other purpose. Many devices will indicate through an icon when location services are operating. We only share this location information with others as approved by you.

You can request to see your personal data.

You can sign into your account to see any personally identifiable information we have stored, such as your name, email, address or phone number. You can also contact us by email to request to see this information.

We may keep data indefinitely.

We may keep data indefinitely.

We don’t share your personal information with marketers.

We generally do not share personally identifiable information (such as name, address, email or phone) with other companies for marketing purposes.

No ad companies collect data through our service.

We do not allow advertising companies to collect data through our service for ad targeting.

You can ask privacy questions.

If you have any questions or concerns about our privacy policies, please contact us:
nebitrams@gmail.com

Vendors access data on our behalf.

In order to serve you, we may share your personal and anonymous information with other companies, including vendors and contractors. Their use of information is limited to these purposes, and subject to agreements that require them to keep the information confidential. Our vendors provide assurance that they take reasonable steps to safeguard the data they hold on our behalf, although data security cannot be guaranteed.

We take steps to protect personal information

Please do not upload confidential data in Adeline Note.  We take reasonable steps to secure your personally identifiable information against unauthorized access or disclosure. We encrypt transmission of data on pages where you provide payment information. However, no security or encryption method can be guaranteed to protect information from hackers or human error.
Information we collect may be stored or processed on computers located in any country where we do business.

Special situations may require disclosure of your data.

To operate the service, we also may make identifiable and anonymous information available to third parties in these limited circumstances: (1) with your express consent, (2) when we have a good faith belief it is required by law, (3) when we have a good faith belief it is necessary to protect our rights or property, or (4) to any successor or purchaser in a merger, acquisition, liquidation, dissolution or sale of assets. Your consent will not be required for disclosure in these cases, but we will attempt to notify you, to the extent permitted by law to do so.
You can review more privacy-related information.
This privacy policy was last updated on 22 Dec 2018. Our privacy policy may change from time to time. If we make any material changes to our policies, we will place a prominent notice on our website or application. If the change materially affects registered users, we will send a notice to you by email, push notification or text.

Friday, 1 June 2018

CocoaPods: upgrade to 1.5.3 with ruby 2.5.1

Problem

See this error when running pod outdated.

Updating spec repo `master`
[!] Failed to connect to GitHub to update the CocoaPods/Specs specs repo - Please check if you are offline, or that GitHub is down

Root Cause

This is because "weak cryptographic standards removed" after 2018 February.

How to Upgrade

Follow the steps by
cocoapods-failed-to-connect-to-github-to-update-the-cocoapods-specs-specs-repo

Run these series of steps to update openssl, then ruby, then cocoapods.

  1. Update brew
  2. Use brew to install latest openssl 2.5.1
  3. Use brew to install : brew install rbenv ruby-build
  4. Use rbenv to install ruby 2.5.1: rbenv install 2.5.1
  5. Use rbenv to set ruby version used : rbenv global 2.5.0
  6. Use rbenv to check ruby version: ruby --version
  7. Use gem to install cocoapods: gem install cocoapods -n /usr/local/bin
  8. Check cocoapods version : pod --version

Use rbenv to install ruby 2.3.7

Run these commands:

  1. Run: rbenv install 2.3.7
  2. Set the ruby version using: export RBENV_VERSION=2.3.7

Sunday, 9 October 2016

Node: Installation and Upgrade

Node is installed using nvm and nodejs packages are install using npm.

Initial Installation

1.  Install nvm
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash
2. Install node version 4
nvm install 4

Upgrade NVM and Node version

1. Upgrade nvm using
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.0/install.sh | bash
 
creationix/nvm/v0.32.0/install.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 10007  100 10007    0     0   5040      0  0:00:01  0:00:01 --:--:--  5038
=> nvm is already installed in /Users/Seet/.nvm, trying to update using git
=> 
=> Source string already in /Users/Seet/.bash_profile
=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="/Users/Seet/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm

2. Upgrade to stable node js 5 version
nvm install 5
######################################################################## 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v5.12.0 (npm v3.8.6)
3. Uninstall node js 4
nvm uninstall 4
4. Set nvm alias to avoid this error: "N/A: version "N/A" is not yet installed."
nvm alias default v5.12.0
5. Useful command for debugging
> nvm alias
default -> v5.12.0
node -> stable (-> v5.12.0) (default)
stable -> 5.12 (-> v5.12.0) (default)
iojs -> N/A (default)
lts/* -> lts/argon (-> N/A)
lts/argon -> v4.6.0 (-> N/A)
> nvm debug
nvm --version: v0.32.0
$SHELL: /bin/bash
$HOME: /Users/Nebitrams
$NVM_DIR: '$HOME/.nvm'
$PREFIX: ''
$NPM_CONFIG_PREFIX: ''
nvm current: v5.12.0
which node: $NVM_DIR/versions/node/v5.12.0/bin/node
which iojs:
which npm: $NVM_DIR/versions/node/v5.12.0/bin/npm
npm config get prefix: $NVM_DIR/versions/node/v5.12.0
npm root -g: $NVM_DIR/versions/node/v5.12.0/lib/node_modules

Upgrade NPM

1. Upgrade nvm using
npm install -g npm@latest

Common Issue for Parse-server Upgrade

This is a common error during upgrade of parse-server.  After upgrade, the npm start may ends with error like this: "Cannot find module 'double-ended-queue'".

If you run npm list, you will see some missing modules such as the followings:
npm ERR! missing: double-ended-queue@^2.1.0-0, required by redis@2.8.0
npm ERR! missing: redis-commands@^1.2.0, required by redis@2.8.0
npm ERR! missing: redis-parser@^2.6.0, required by redis@2.8.0
 You can try to delete the package-lock.json and node_modules folder, following by re-install.

rm -rf package-lock.json node_modules/
npm i --no-optional
npm dedupe
npm up
Refer to https://github.com/npm/npm/issues/19393 for more information.

Friday, 7 October 2016

MongoDB : regular version upgrade

The local MongoDB instance was installed using brew.

Initial Installation

  1. Install Xcode command-line toolsxcode-select --install
  2. install home-brew

Upgrade locally installed mongodb

1. Upgrade brew by running
"brew update"
2. Upgrade mongodb by running
"brew upgrade mongodb"
==> Upgrading 1 outdated package, with result:
mongodb 3.2.10
==> Upgrading mongodb
==> Installing dependencies for mongodb: openssl
==> Installing mongodb dependency: openssl
==> Downloading https://homebrew.bintray.com/bottles/openssl-1.0.2j.el_capitan.b
######################################################################## 100.0%
==> Pouring openssl-1.0.2j.el_capitan.bottle.tar.gz
==> Using the sandbox
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
  /usr/local/etc/openssl/certs

and run
  /usr/local/opt/openssl/bin/c_rehash

This formula is keg-only, which means it was not symlinked into /usr/local.

Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries

Generally there are no consequences of this for you. If you build your
own software and it requires this formula, you'll need to add to your
build variables:

    LDFLAGS:  -L/usr/local/opt/openssl/lib
    CPPFLAGS: -I/usr/local/opt/openssl/include

==> Summary
🍺  /usr/local/Cellar/openssl/1.0.2j: 1,695 files, 12M
==> Installing mongodb
==> Downloading https://homebrew.bintray.com/bottles/mongodb-3.2.10.el_capitan.b
######################################################################## 100.0%
==> Pouring mongodb-3.2.10.el_capitan.bottle.tar.gz
==> Caveats
To have launchd start mongodb now and restart at login:
  brew services start mongodb
Or, if you don't want/need a background service you can just run:
  mongod --config /usr/local/etc/mongod.conf
==> Summary
🍺  /usr/local/Cellar/mongodb/3.2.10: 18 files, 245.2M

Upgrade local mongodb from 3.4.18 to 3.6

This is to document the process of upgrading from currently installed 3.4.18 to 3.6.11.  Using brew upgrade doesn't work for me and I used brew install mongodb@3.6.  However, the drawback is I only managed to install 3.6.8 (not sure why 3.6.11 is not available).  Refer to this link for more information.  Upgrade to specific version of MongoDB

1. Prepare the data by running this using mongo shell.
db.adminCommand( { setFeatureCompatibilityVersion: "3.4" } )
2. Upgrade brew by running will result in installing the latest which is 4.0 as of May 2019
"brew upgrade mongodb"
3. Install a specific version by using
"brew install mongodb@3.6"
4. Update the link using
"brew unlink mongodb@3.4"
"brew link --force mongodb@3.6"
5. Open a new shell and check the default MongoDB version
mongod --version
db version v3.6.8
git version: <snipped>
OpenSSL version: OpenSSL 1.0.2r  26 Feb 2019
allocator: system
modules: none
build environment:
    distarch: x86_64
    target_arch: x86_64
5. If you see this error when you start up mongod.  Then you need to set.  Read error-while-upgrading-mongodb-from-3-2-to-3-6
IMPORTANT: UPGRADE PROBLEM: The data files need to be fully upgraded to version 3.4 before attempting an upgrade to 3.6; see http://dochub.mongodb.org/core/3.6-upgrade-fcv for more details.
 6. If you need to switch back to mongodb version 3.4.  Use the brew link and unlink.  After that, you can switch back to 3.6 by unlink and link again.
"brew unlink mongodb@3.6"
"brew link --force mongodb@3.4"

Upgrade mLab mongodb version

General steps for upgrade:
  1. Check the mLab upgrade guide.
  2. Test the application in staging environment
Once all test is completed, upgrade the mLab using Tool -> version.

Friday, 20 May 2016

ParseServer: managing mLab test environment

Prerequisites

  1. You have completed the setup of a production mLab database.
  2. You have mongoLab client installed in your computer so that you can run these
    1. mongodump
    2. mongorestore

Objective

Copy from mLab production database to another mLab staging database.

mLab cloud backup vs local backup

The copy of production database to test database is achieved using backup and restore mechanism. mLab provides cloud based backup and restore functionality using the web based admin page.  However, each backup cost 50 cents.  Alternatively, you can achieve this free of charge by installing your own mongoLab client in your computer and perform backup to your local computer and then restore to another test database in mLab.

Copy mLab database from production to staging using local backup

You will first need to run a mongodump to backup your mLab production database to your local PC.  After that you run mongorestore to restore your local PC database backup to another mLab staging database.  

MongoDB provides two mechanisms for importing and exporting data. One way is via the mongoimport and mongoexport utilities. These allow you to import and export JSON and CSV representations of your data. The other way is with mongorestore and mongodump utilities which deal with binary dumps.

The commands to dump, delete all tables/data and restore are as follows:
  1. mongodump -h <production-hostname> -d <production-database-name> -u <user> -p <password> -o <output directory>
  2. mongo <staging-hostname>/<staging-database-name> -u <user> -p <password> --eval "db.dropDatabase();"
  3. mongorestore -h <staging-hostname> -d <staging-database-name> -u <user> -p <password> <input db directory>

ParseServer: managing Heroku test environment

Prerequisites

You have completed the setup of app in both
  1. local, i.e your own computer
  2. hosted on heroku, i.e this is the app that you deployed using "git push heroku master"
Refer to this heroku page for the details on creating staging, integration environments for the same application.  All the command below need to be ran in the heroku directory.  Heroku toolbelt is installed and you are logon using your heroku credential.

Objective

Setup a staging Heroku application.  A staging application is useful for testing new features in a production lookalike environment before releasing to production.

Checking your existing Git Remote

All applications on heroku are created with the default git remote as "heroku".  You can check the git remote using this command:
git remote -v
The command returns remotes as follows.  The heroku remote is the app that I deployed to the heroku.  The origin remote came from the git clone command when I clone from the parse-server-example git.
> origin    https://github.com/ParsePlatform/parse-server-example.git (fetch)
> origin    https://github.com/ParsePlatform/parse-server-example.git (push)
> heroku    https://git.heroku.com/elochallenge.git (fetch)
> heroku    https://git.heroku.com/elochallenge.git (push)
 

In this setup, I want to create elochallengestaging app from elochallenge app.  After the setup, I will have these 2 applications in Heroku.
  1. elochallenge
  2. elochallengestaging

Creating a Staging Environment

Run the following command to create a staging environment.
heroku fork --from elochallenge --to elochallengestaging
Add a new git remote using this command.
git remote add elochallengestaging https://git.heroku.com/elochallengestaging.git
Run this again to confirm that remote is created successfully.
 git remote -v

Setting Configuration Variables

After the new environment is created.  You will need to set the configuration variables.  Run these command line.
  1. heroku config:set DATABASE_URI=xxx --remote  elochallengestaging
  2. heroku config:set MASTER_KEY=xxx --remote  elochallengestaging
  3. heroku config:set SERVER_URL=xxx --remote  elochallengestaging
You can also update the configuration variable using Heroku web admin page.

Publish Changes to Staging and Production Environment

When you are ready to test your code in staging, run the following command to push to staging.
git push elochallengestaging master
After testing in the staging environment is completed, you may push your changes to production.
git push heroku master

Pulling latest code from ParseServer github

The git remote that you checked out the source code via "git clone" will be updated with new releases.  Once you are ready to get the latest release, run one of the git pull command below from your local git folder.

  • git pull https://github.com/ParsePlatform/parse-server-example.git
  • git pull origin

If you see conflicts, check for the filename with conflict and use editor to resolve the merge conflict manually.  For example, this is a conflict in package.json
remote: Counting objects: 11, done.
remote: Total 11 (delta 6), reused 6 (delta 6), pack-reused 5Unpacking objects: 100% (11/11), done.
From https://github.com/ParsePlatform/parse-server-example   5eea333..084fa07  master     -> origin/master * [new branch]      parse-server-version -> origin/parse-server-versionAuto-merging package.json
CONFLICT (content): Merge conflict in package.json
Auto-merging index.jsAutomatic merge failed; fix conflicts and then commit the result.

After resolving conflicts, run the npm to get the latest.
  • npm outdated : to list the outdated modules. Sample output as follows.
Package       Current  Wanted  Latest  Locationexpress        4.13.4  4.13.4  4.14.0  express parse-server   2.2.10  2.2.14  2.2.14  parse-server
  • npm update : to get the latest modules to local computer
  • npm list : to list all the modules installed locally
Once you are ready, do a git add, git commit and deploy it to the staging environment by using git push command.
  • git push elochallengestaging master

Setting Git Defaults

You can set the git push defaults to the staging environment.  Run the following command to list all the git config.
git config -l
Run this to setup the push default to elochallengestaging.
git config push.default elochallengestaging
After setting up the default, you can push to the elochallengestaging by running this command.
git push

Friday, 24 October 2014

123 Dandelion - a fun way to learn odd, even numbers and times table

I designed this game for lower primary school children to learn odd numbers, even numbers and times table.
Click here to download from Apple AppStore
Choose a number series
The game starts with 5 numbers
More numbers at higher levels



Wednesday, 15 October 2014

123 Dandelion Terms of Use

Terms of Use

Thank you for choosing 123 Dandelion App! This is an agreement between you and App creator  that describes the terms of use for 123 Dandelion App and services.  You should review the entire agreement because all of the terms are important and together create this contract that applies to you.

Warranties

Please note we do not provide warranties.

Limitation of Liability

Whilst every effort has been made in building this 123 Dandelion App, I am not to be held liable for any special, incidental, indirect or consequential damages or monetary losses of any kind arising out of or in connection with the use of the this App and information derived from this App.

This 123 Dandelion App is here purely as a service to you, please use it at your own risk. Do not use the App information for anything where loss of life, money, property, etc.

Privacy Policy

We collect personal and activity data, which may be linked.
We use technologies like cookies (small files stored on your browser), web beacons, or unique device identifiers to identify your computer or device so we can deliver a better experience. Our systems also log information like your browser, operating system and IP address.

We also may collect personally identifiable information that you provide to us, such as your name, address, phone number or email address. With your permission, we may also access other personal information on your device, such as your phone book, calendar or messages, in order to provide services to you. If authorized by you, we may also access profile and other information from services like Facebook.

Our systems may associate this personal information with your activities in the course of providing service to you (such as pages you view or things you click on or search for).

We do not knowingly contact or collect personal information from children under 4. If you believe we have inadvertently collected such information, please contact us so we can promptly obtain parental consent or remove the information.

We collect or share your location only with permission.
In serving you, we may use or store your precise geographic location, if you give us permission to do so. We do not use or share this data for any other purpose. Many devices will indicate through an icon when location services are operating. We only share this location information with others as approved by you.

You can request to see your personal data.
You can sign into your account to see any personally identifiable information we have stored, such as your name, email, address or phone number. You can also contact us by email to request to see this information.

We may keep data indefinitely.
We may keep data indefinitely.

We don't share your personal information with marketers.
We generally do not share personally identifiable information (such as name, address, email or phone) with other companies for marketing purposes.

No ad companies collect data through our service.
We do not allow advertising companies to collect data through our service for ad targeting.

You can ask privacy questions.
If you have any questions or concerns about our privacy policies, please contact us:
nebitrams@gmail.com

Vendors access data on our behalf.
In order to serve you, we may share your personal and anonymous information with other companies, including vendors and contractors. Their use of information is limited to these purposes, and subject to agreements that require them to keep the information confidential. Our vendors provide assurance that they take reasonable steps to safeguard the data they hold on our behalf, although data security cannot be guaranteed.

We take steps to protect personal information.
We take reasonable steps to secure your personally identifiable information against unauthorized access or disclosure. We encrypt transmission of data on pages where you provide payment information. However, no security or encryption method can be guaranteed to protect information from hackers or human error.

Information we collect may be stored or processed on computers located in any country where we do business.

Special situations may require disclosure of your data.
To operate the service, we also may make identifiable and anonymous information available to third parties in these limited circumstances: (1) with your express consent, (2) when we have a good faith belief it is required by law, (3) when we have a good faith belief it is necessary to protect our rights or property, or (4) to any successor or purchaser in a merger, acquisition, liquidation, dissolution or sale of assets. Your consent will not be required for disclosure in these cases, but we will attempt to notify you, to the extent permitted by law to do so.

You can review more privacy-related information.
This privacy policy was last updated on 15 October 2014. Our privacy policy may change from time to time. If we make any material changes to our policies, we will place a prominent notice on our website or application. If the change materially affects registered users, we will send a notice to you by email, push notification or text.

Thursday, 8 May 2014

Spelling 1942 Version 1.5.0 - a fun way to learn spelling

Spelling 1942, provides a fun way to learn spelling.  Every school gives out spelling list.  Your children can learn the school spelling list in this app and reinforce the learning by playing game this simple game.

The spelling lists are contributed by parents and teachers.  It is organised into Country, School, Level hierarchy.  School teachers are encouraged to submit their spelling list in MS Word file by email and I will make it available in this game.

A player can play the game in practise and challenge mode.  The practise mode is useful for the learning the words.  The challenge mode is designed to encourage children to aim for higher score and avoid making mistake.

In level 1 game play, player listen to pronunciation and shot the aeroplane which carry the pronounced word.  If the player is confident enough, he/she can shoot a helicopter and spell the pronounced word to get 10x the score.
Shoot helicopter and spell the word
to get 10x score

In level 2 game play, the game is more difficult because some "mutated" words will be appear as distractions.  For example, a word "spad" will appear instead of "sped" to test whether the player can pick up the right word.  If the player shoot the wrong word, he/she will get a penalty score.
Level 2 game play with "mutated" words

The game supports English, Chinese and Malay language.  It should be able to support any language in iPhone Siri.  Feel free to drop me a request on a new language if you are interested in.

Wednesday, 26 March 2014

Pebble Watchface - Chinese Calligraphy Clock

I got my Pebble Smart Watch on Sunday. I really like it since I can read SMS and see incoming calls from the watch. On Monday, I moved on to play with the sample code for 2 days. On Wednesday, I published a Chinese calligraphy watch face on Pebble Store. The Pebble development environment is well designed. It is quite easy to pick up if you have C language background. Next, I will try to create educational game. Drop me a note if you have some ideas :-)

This is the designed Pebble Watchface in 168 x 144 pixels.


You can download this Watchface (Chinese Clock) into your Pebble watch using iPhone or Android.  I like the watch and the programming environment.  Now, I am looking for ideas to create educational games :-)

This is my Chinese Clock Watchface on Pebble Appstore



Saturday, 8 February 2014

Spelling 1942 - a fun way to learn spelling

Spelling 1942, provides a fun way to learn spelling.  Every school gives out spelling list.  Your children can learn the school spelling list in this app and reinforce the learning by playing game this simple game.

So far it supports English, Chinese and Malay language.  It should be able to support any language in iPhone Siri.  Feel free to drop me a request on a new language if you are not sure.

Listen to pronunciation and shoot the word
During the game play, the children will listen to the pronunciation and shoot the correct word.  The children will gain and lose points depending on whether he shoots the right words.

Spelling List Picker
The spelling list is organised into Country, School, Level hierarchy.  First you will choose a country, followed by a school and a level.  You can then choose the spelling list available.

Words in a spelling list
In this screen, you can do revision on the words in the spelling list.

If you cannot find your children school's spelling list, you may download iLoveSpelling and start creating spelling list for your own children.
Download iLoveSpelling
Link to iLoveSpelling in Settings
The spelling list that you created will also benefits the other children since it will be shared to all.  iLoveSpelling App was launched in 2012 and it benefits my sons and other children.  It provides an easy channel to share spelling list among parents and students.  One of my neighbour loves it since the mother doesn't read Chinese and the father who know Chinese language always help to enter the Chinese spelling list in iLoveSpelling App.  This way, the mother can still provide the coaching for her son.

Saturday, 18 January 2014

Spelling 1942 Terms of Use

Terms of Use

Thank you for choosing Spelling 1942 App! This is an agreement between you and App creator  that describes the terms of use for Spelling 1942 App and services.  You should review the entire agreement because all of the terms are important and together create this contract that applies to you.

Warranties

Please note we do not provide warranties.

Limitation of Liability

Whilst every effort has been made in building this Spelling 1942 App, I am not to be held liable for any special, incidental, indirect or consequential damages or monetary losses of any kind arising out of or in connection with the use of the this App and information derived from this App.

This Spelling 1942 App is here purely as a service to you, please use it at your own risk. Do not use the App information for anything where loss of life, money, property, etc.

Privacy Policy

We collect personal and activity data, which may be linked.
We use technologies like cookies (small files stored on your browser), web beacons, or unique device identifiers to identify your computer or device so we can deliver a better experience. Our systems also log information like your browser, operating system and IP address.

We also may collect personally identifiable information that you provide to us, such as your name, address, phone number or email address. With your permission, we may also access other personal information on your device, such as your phone book, calendar or messages, in order to provide services to you. If authorized by you, we may also access profile and other information from services like Facebook.

Our systems may associate this personal information with your activities in the course of providing service to you (such as pages you view or things you click on or search for).

We do not knowingly contact or collect personal information from children under 4. If you believe we have inadvertently collected such information, please contact us so we can promptly obtain parental consent or remove the information.

We collect or share your location only with permission.
In serving you, we may use or store your precise geographic location, if you give us permission to do so. We do not use or share this data for any other purpose. Many devices will indicate through an icon when location services are operating. We only share this location information with others as approved by you.

You can request to see your personal data.
You can sign into your account to see any personally identifiable information we have stored, such as your name, email, address or phone number. You can also contact us by email to request to see this information.

We may keep data indefinitely.
We may keep data indefinitely.

We don't share your personal information with marketers.
We generally do not share personally identifiable information (such as name, address, email or phone) with other companies for marketing purposes.

No ad companies collect data through our service.
We do not allow advertising companies to collect data through our service for ad targeting.

You can ask privacy questions.
If you have any questions or concerns about our privacy policies, please contact us:
nebitrams@gmail.com

Vendors access data on our behalf.
In order to serve you, we may share your personal and anonymous information with other companies, including vendors and contractors. Their use of information is limited to these purposes, and subject to agreements that require them to keep the information confidential. Our vendors provide assurance that they take reasonable steps to safeguard the data they hold on our behalf, although data security cannot be guaranteed.

We take steps to protect personal information.
We take reasonable steps to secure your personally identifiable information against unauthorized access or disclosure. We encrypt transmission of data on pages where you provide payment information. However, no security or encryption method can be guaranteed to protect information from hackers or human error.

Information we collect may be stored or processed on computers located in any country where we do business.

Special situations may require disclosure of your data.
To operate the service, we also may make identifiable and anonymous information available to third parties in these limited circumstances: (1) with your express consent, (2) when we have a good faith belief it is required by law, (3) when we have a good faith belief it is necessary to protect our rights or property, or (4) to any successor or purchaser in a merger, acquisition, liquidation, dissolution or sale of assets. Your consent will not be required for disclosure in these cases, but we will attempt to notify you, to the extent permitted by law to do so.

You can review more privacy-related information.
This privacy policy was last updated on 18 January 2014. Our privacy policy may change from time to time. If we make any material changes to our policies, we will place a prominent notice on our website or application. If the change materially affects registered users, we will send a notice to you by email, push notification or text.

Wednesday, 16 October 2013

Kopi C App is upgraded for iOS 7

This is the very first experimental app that I created.  It's finally a good time to revisit this app.  I have clean up the items so that all items have no price since the price was never accurate before.  It is quite easy to recompile and publish the old app.  Now the latest version 2.2.1 of Kopi C App supports both iOS6 and iOS7.

Kopi ordering screen

Screen with chosen orders

Add item screen

Shop screen

Teh Tarik menu

Tuesday, 15 October 2013

Supporting iOS 7 with Three Quarter Tank Version 1.2.1

iOS 7 screens are amazing clean and elegant.

It took me a while to get used to the new Xcode 5.0 today. It's not too difficult but I got to read through the iOS 7 UI Transition Guideline to understand how to support both iOS 6 and 7.  I will support iOS 6 for limited period of 6 months.  After which, I will only support iOS 7.

Screen for 3/4 Mileage

Screen for Top Up Amount


Screen for Choosing Custom

iOS Maps App 
Fuel Efficiency Converter

Fuel Efficiency Calculator