Tuesday, September 06, 2016

AngularJS simple add, delete HTML example

If you are just getting starting with AngularJS, then you may find a humongous amount of tutorial and articles on the internet which can help you get confused and lost pretty quickly.

If you know HTML and JavaScript/Jquery and just quickly want to see how AngularJS would change your regular HTML vs JavaScript interaction, then perhaps this quick article may help you. In this demo, I will not be using any server side stuff. No ASP.NET, no PHP. It will be a plain old HTML page, and a small bit of JavaScript.

As of writing, it is based on AngularJS 1.5.8.

In this demo, I will provide user the ability to provide his first name, last name and gender. This information will get added to a table and will be dynamically updated when new row is added. The user will also be able to select one or more rows, and delete them.

All this will happen on the client side, with no postback happening. Additionally, to keep things simple I am not adding ayn session management or database part so nothing will persist if you re-open the page.



JSFiddle: https://jsfiddle.net/saurabhkum/ftod4zqh/


Raw code below:

HTML

<!DOCTYPE html>
<html lang="en"> 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AngularJS Demo</title>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">


    
    
</head>
<body data-ng-app="angulardemo" data-ng-controller="appCtrl" class="container">

<table id="table" class="table table-responsive">
<thead>
<tr>
    <th> </th>
    <th>#</th>
    <th>First:</th>
    <th>Last:</th>
    <th>Gender</th>
</tr>
</thead>
<tbody>
    <tr class="records" data-ng-repeat="record in records | orderBy:'-rating'">
        <td><input type="checkbox" data-ng-model="record.selected"/></td>
        <td>{{$index + 1}}</td>
        <td>{{ record.fname }}</td>
        <td>{{ record.lname }}</td>
        <td>{{ record.gender }} </td>
    </tr>
    <tr>
        <td><input data-ng-hide="!records.length"  type="button" data-ng-click="remove()" class="btn pull-left" value="X"></td>
        <td> </td>
        <td> </td>
        <td> </td>
        <td> </td>
    </tr>
    </tbody>
</table>

<hr/>
<form >
<div class="row"><p>
Enter the details below to add new row:
</p></div>
<div class="row">
      <div class="col-md-3"><strong>First Name  </strong><input type="text"  data-ng-model="record.fname" /></div>
      <div class="col-md-3"><strong>Last Name  </strong><input type="text" data-ng-model="record.lname" /></div>
      <div class="col-md-3 form-group">
            <label><input type="radio" name="gender" value="male" checked data-ng-model="record.gender">Male</label>
            <label><input type="radio" name="gender" value="female" data-ng-model="record.gender">Female</label>
      </div>
      <div class="col-md-3"> <input type="button" data-ng-click="addNew()" class="btn btn-primary addnew pull-right" value="Add New"> </div>
</div>
</form>
<hr/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<script type="text/javascript" src="myscript.js"></script>                      
</body>
</html>


JavaScript


var app = angular.module('angulardemo', []);
app.controller('appCtrl', ['$scope', function($scope) {
    $scope.record = {}; 
    $scope.records=[];
    $scope.addNew = function(){
        $scope.records.push({ 
            'sr': $scope.records.length, 
            'fname':$scope.record.fname,
            'lname': $scope.record.lname, 
            'gender': $scope.record.gender
        });     
    };
    
     $scope.remove = function(){
                var newDataList=[];
                $scope.selectedAll = false;
                angular.forEach($scope.records, function(selected){
                    if(!selected.selected){
                        newDataList.push(selected);
                    }
                }); 
                $scope.records = newDataList;
            };
}]);

Monday, August 22, 2016

Gulp fails on new Visual Studio project, and does not see tasks

So you decide to give the new yet powerful 'Gulp' tool a try and fire up the Visual Studio 2015 IDE. You follow a basic tutorial or document to create a simple Hello World application. Next, you might create the gulpfile.js and define a couple of tasks to automate. Happy with your quick Gulp example project, you execute your project, and get an error.

Error 1

If the error you get is something like below:

cmd.exe /c gulp --tasks-simple
'gulp' is not recognized as an internal or external command,
operable program or batch file.

then, this is what may help you:



  1. Install the latest Node.js from https://nodejs.org/en/ . I installed v4.5.0 as of writing.
  2. Next, open your Windows Command Prompt
  3. Type node -v and hit enter. If you see the version shown then Node is now installed.
  4. Next type on the command prompt: C:\Users\Saurabh>npm install -g gulp
  5. This should now install Gulp on your machine ready for use in your project

Error 2

If the error you get is something like below, where your Task Runner Explorer is not able to see any Gulp tasks and gives "No tasks found" error:



For this error to go away,
  1. Open Command Prompt
  2. Go to the folder of your project, and enter command npm install gulp
  3. Press enter to execute
  4. Now, if you refresh your Task Runner, it should load the tasks




Monday, April 04, 2016

SSL certificate problem on Azure running PHP

So recently I was trying out a piece of code in PHP, and wanted to hit the Google reCaptcha server, but my curl requests all failed for some reason.

I then added an 'echo curl_error($curl);' to my code and was greeted with a "SSL certificate problem: unable to get local issuer certificate" error. Now this was much more meaningful, than a blindly failing curl request.

So here is how I fixed this issue:

Physical file configuration:

  1. Open your Azure file structure, perhaps using your favorite FTP client. I swear by FileZilla!
  2. In your site folder structure, create a folder say, "ini" under the "site" folder.
  3. Create another folder under the 'site' folder named 'ca'
  4. Go to https://curl.haxx.se/docs/caextract.html and download the 'cacert.pem' file. Place this file inside the 'ca' folder
  5. Inside 'ini' folder create a text file 'extensions.ini'
  6. Add the following line to the 'extensions.ini' file - "curl.cainfo=d:\home\site\ca\cacert.pem"
Azure Portal configuration:
  1. Head to your portal.azure.com account
  2. Refer to the documentation on how to configure custom PHP settings.
  3. Open the 'Application Settings' page for your offending Web App.
  4. On this page, under 'App Settings', set 'PHP_INI_SCAN_DIR' to 'd:\home\site\ini'
  5. Remember to hit 'Save' on top of this page, and then restart this Web App.

Wait for a few seconds, and try opening your web page again. My error vanished at this pointed and I was back in business!

Hope this helps someone out there reading this page.

Tuesday, January 26, 2016

Fitbit Sync Battery Drain - Tasker Profile

Recently I got myself a Fitbit Charge HR, which added to my new year resolve to do something proactive to improve my health. Let's see how this resolve stands beyond the first few weeks, but that is out of scope for this blog entry.

I have an Android Nexus 5 phone where I installed my Fitbit app, and via Bluetooth the app syncs with my Fitbit. The device should ideally last around 5 days with a fresh charge, but I noticed mine was lasting hardly for two days! Together with the proprietary charge cable, this, I saw as an added pain.

Quick fixes included:



  • Make very sure that the FitBit is updated to any latest firmware version
  • Turning off the 'Quick View' feature of my Charge HR
  • Turning off  'Add Day Sync'. This was hitting my fitbit almost every 15 minutes or so!
  • Turning off  'Always Connected'. This was bad too for both my phone and the device battery life
I feel this did help a lot in saving battery life of my Fitbit, but now I had to manually remember to sync. I also do not like keeping my bluetooth always open. So I needed someway to automate my fitbit getting synced once or twice a day.

Check on my settings on the shown screenshot of my FitBit.

Tasker to the rescue!

I happen to have Tasker on my phone, which I paid for for it's ease of automating almost anything on my phone. I made a quick profile using it, to solve my requirements.

I can confirm that post my tasker profile, and the above FitBit config changes, instead of max 2 days, I am easily getting 5+ days now!

Profile Features:

Version 1.1 (Feb 19, 2016)
Have tweaked the profile to make it more reliable.
One major change in this version is that during sync, I turn off wifi, and rely on the mobile data for internet connectivity. At least for my testing, I have found this to be much more reliable for some reason in making the FitBit to sync.

I also check if internet is connected, before opening the App. Additionally a few strategic delays were added to allow the system to stabilize post a setting change.

Till now, I am getting sync perfectly as planned, twice a day (7:30 AM and 9:00 PM, but ofcource you can change these times if you need to).

Original version (Jan 26, 2016)
  1. Sync my Fitbit twice a day, at 7 AM and then at 8 PM. This way my curious self gets to see in the morning how was my sleep yesterday, and in the evening to see how my day went.
  2. The profile would turn on bluetooth at the defined time for 5 minutes and will wake up the phone
  3. during this time the profile would also launch the Fitbit app so that a manual sync begins
  4. After 5 minutes, the bluetooth would be turned back off
  5. I think tasker uses the efficient Android API to try to wake up the phone at "approximately" the times defined to try club other wake requests
Download the latest profile XML from here

Do let a comment if this helped you, or if you may improve this further.

Monday, December 14, 2015

Setting up ImageMagick for PHP on Azure

Recently I was trying to get PHP+MySQL web application setup on Azure. I was excited to see how Azure would play with non Microsoft platforms. It was quite promising to see that Azure gave me a web applicaiton with PHP out of the box.

Now I wanted to stretch it further by trying to setup ImageMagick extension. Now installing ImageMagick has historically not been the cleanest process. With numerous libraries floating around it has been a less than ideal experience. I did finally get it working though, thanks to the pointer by Brij Raj Singh at StackoverFlow and the article by Mangesh. I am outlining here the steps I followed, tweaking Mangesh's steps a bit to get ImageMagick working on default PHP installation of Azure.

I am assuming in Azure you already have a web application with PHP enabled, and you are using the latest PHP 5.6 from Azure App Settings.


  1. Download the file http://windows.php.net/downloads/pecl/releases/imagick/3.3.0rc2/php_imagick-3.3.0rc2-5.6-nts-vc11-x86.zip and extract it in a temporary folder
  2. From https://www.imagemagick.org/script/binary-releases.php, scroll to the 'Windows Binary Release' section and download the latest file ending with Q16-x86-dll.exe. (as of writing it was  http://www.imagemagick.org/download/binaries/ImageMagick-6.9.2-8-Q16-x86-dll.exe )
  3. Install the above downloaded exe file on your windows personal machine/laptop
  4. Now from within the FTP of your Azure site, create a folder named 'ext' in your root folder. So the path to this folder would be something like /site/ext
  5. Create a folder named 'ini' in your root folder. So the path to this folder would be something like /site/ini
  6. Create a folder named 'imagickwin' in your root folder. So the path to this folder would be something like /site/imagickwin
  7. In the ini folder created above, create a new file named extensions.ini
  8.  The ini file created above should have the following text extension=d:\home\site\ext\php_imagick.dll 
  9. In Azure portalgo to Application Settings for your app resource, and change PHP to the latest version 5.6
  10. In the Application Settings itself, create a key named 'PHP_INI_SCAN_DIR', and provide its value as d:\home\site\ini . This is as described at https://azure.microsoft.com/en-us/documentation/articles/web-sites-php-configure/ site.



  11. Copy all the Core*.dll files from 'C:\Program Files (x86)\ImageMagick-6.9.2-Q16' to the /site/imagickwin folder.
  12. Copy all DLL files from 'C:\Program Files (x86)\ImageMagick-6.9.2-Q16\modules\coders' to the /site/imagickwin folder.
  13. Now go to the folder where you extracted 'php_imagick-3.3.0rc2-5.6-nts-vc11-x86.zip' archive contents. From this, copy all the dll files to /site/ext folder
  14. Next is the most important step - Create a new file namedapplicationHost.xdt directly under the at the site folder level. This file should have the below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> 
  <system.webServer> 
    <runtime xdt:Transform="InsertIfMissing"> 
      <environmentVariables xdt:Transform="InsertIfMissing"> 
        <add name="PATH" value="%PATH%d:\home\site\ext\;" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" /> 
        <add name="MAGICK_HOME" value="d:\home\site\ext\" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" /> 
        <add name="MAGICK_CODER_MODULE_PATH" value="d:\home\site\imagickwin\" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" /> 
      </environmentVariables> 
    </runtime> 
  </system.webServer> 
</configuration>

Now, restart your web application, and load phpinfo() to verify that you are seeing something like below:


And you are done!

Tuesday, September 22, 2015

Scanning barcodes, using Raspberry Pi


My objective for this proof of concept project was to use a regular webcam to scan for barcodes, parse them and transmit the same via a REST service, using Raspberry Pi as the hardware platform.

I believe a lot of people have already "been there, done that", but somehow I found no single source of information to help me through all the obstacles I came across while trying to scan barcode using Raspberry Pi. So here is my version of how I went about it.


Ingredients

  1. I used the Raspberry Pi B+ described here
  2. I used a Logitech webcam for better scan quality, and automatic focus
  3. Logitech wireless keyboard for ease of coding as listed here
  4. I used power source via USB port
  5. I did NOT use a commercial barcode scanner, though that I had kept as a Plan B, if the code would not have worked via the webcam. Using that is actually very trivial, because once connected via USB, it acts as a regular keyboard. So any barcode it scans, Raspberry should ideally see it as keystrokes containing the barcode data. Anyway, I cannot guarantee that because I did not need to go to this path.
  6. Portable keyboard and optionally mouse for interacting with the Raspberry

Bake the cake time!


I spent almost till midnight with the raspberry trying to understand from scratch how it works, and how it reacts to Python as the base programming language. So I was able to hookup my Logitech wireless keyboard+mouse to the board using the Logitech Unifying dongle. I did not expect the tiny Raspberry to work with Unifying, but it did work instantly post a reboot! Now I had keyboard and mouse access to my Raspberry.

Next, I connected ethernet and saw Raspberry connect to the Internet. I realized later that this was a critical step, as I would soon be downloading a lot of libraries/packages for this project.

I tried to write a hello world Python script and all Bash scripts require the code to begin with #, but I realized that the keyboard was not allowing me to type '#' !! Bummer. I had to dig into Raspberry preferences, and select keyboard style 101, for English US. Post a reboot, my gained the power to type '#' and was happy. While in the settings, I also set the clock and changed the timezone to my preferred CST timezone.

Next I connected the USB external webcam. This was used so I could start off with better quality optics, and the capability of auto focus. To begin using the webcam, I had to make my Raspberry webcam aware. 

After a lot of digging I realized that I needed to install a number of libraries to make Raspberry ready for action. I also had to install 'pillow', which works as an alternative for PIL image manipulation library. I also installed httpplib2 for my other part of this project, which is supposed to make REST service requests.

I installed the libraries in the below order:

sudo apt-get install python-dev
sudo apt-get install python-pip
sudo pip install pillow
sudo apt-get install python-httplib2



Next,  I issued the below command to install USB webcam package. This allows for leveraging an external USB based webcam, with autofocus capabilities and user configurable resolution.

sudo apt-get install fswebcam

I could now take a screenshot using the command

fswebcam image.jpg

I explored if I could change the resolution of the image to increase/decrease the resolution at will. I later found that indeed, that could be done using the command:

fswebcam -r 1280x720 –-no-banner image2.jpg


At this stage, I was feeling confident that Raspberry had started to respond to my whims.

What if i could run a cron job to take screenshots at set intervals? I was able to do that by issuing:

Crontab –e


This allowed me to setup cron to repeat, and loop for continuous image shots

All this was fun, but till now all that was achieved was to make the webcam work. Nothing done so far, had anything to do with the real parsing of barcodes.

Enter ZBar. This is an Open Source library, which is excellent in what it advertises. It can scan and parse a lot of different types of barcodes, and is very configurable. Unfortunately, the original Zbar library id not work for me as it was not well maintained. I spent a lot of time trying to work but got stuck at one place or the other. The original Zbar is quite old code and not meant for this version of ARM processor. Then I discovered a fork of Zbar at Github, which was a PHP wrapper for the original Zbar. This was available here which had superb sample scripts too to get started.

I installed python Zbar dependencies by executing:

sudo apt-get install python-zbar
sudo apt-get install libzbar-dev


Next I put the script files from the above URL on Raspberry in a folder, and then from that folder executed:

python setup.py install –user

The above went successfully and Zbar was now completely ready to do its magic.


Now, together with Zbar I had four available capability ready to be used as per will:
  • Take an image capture using fswebcam, and process later with zbar
  • Use video stream to read the first available barcode
  • Use video stream to read as many stable barcodes as possible
  • Use video stream to read continuous barcodes, till a mouse/keyboard activity happens


Here is an example of a simple script I wrote to take screenshots and store it with a unique name each time

#!/bin/bash

DATE=$(date +"%Y-%m-%d_%H%M%S")

fswebcam -r 1280x720 -i 0 --delay 1 --frames 10 --skip 5 --no-banner /home/pi/Documents/saurabh/webcam_cap/$DATE.jpg


And here is the final script, which was majorly provided as a Zbar sample script which initializes the webcam, and then run continually waiting for a valid barcode to appear. As soon as a barcode is detected, it is scanned, parsed and the the script ends. Just what I needed for this part of this proof of concept project.

#!/usr/bin/python
from sys import argv
import zbar

# create a Processor
proc = zbar.Processor()

# configure the Processor
proc.parse_config('enable')

# initialize the Processor
device = '/dev/video0'
if len(argv) > 1:
    device = argv[1]

#proc.request_size(800,480)

proc.init(device)

# enable the preview window
proc.visible = True

# read at least one barcode (or until window closed)
proc.process_one()

# hide the preview window
proc.visible = False

# extract results
for symbol in proc.results:
    # do something useful with results
    print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data


Here is a screenshot of the code in action. Notice that the barcode got read even when scanned upside down.


Up, Up and Away!


Here is a bonus script. In case you require your little Raspberry to let the world know about this barcode just read, or otherwise, then here is how I called a REST service using another Python script:

import httplib2
import json
import time
import datetime

def sendHTTPRq(barcode):
    httplib2.debuglevel     = 0
    http                    = httplib2.Http()
    content_type_header     = "application/json"

    url = "http://www.YOURSERVER.COM/JSONSVC/" +str(barcode)

    data = {    'Id':         barcode,
                'CreatedDateTime':    str(datetime.datetime.now()),
                'CreatedUser':    'saurabh',
                'UpdatedDateTime':    str(datetime.datetime.now())
           }

    headers = {'Content-Type': content_type_header}
    print ("Posting %s" % data)

    #while True:
    response, content = http.request( url,
                                      'GET',
                                      json.dumps(data),
                                      headers=headers)
    print (response);
    print (content);
    #time.sleep(3)
    return;

That's It. Do leave a comment if this may have helped you, or if you have suggestions for improvement, or a better process flow.

Thursday, September 10, 2015

Using TortoiseGIT on Windows, with BitBucket

A very common requirement for a developer is to host code on BitBucket, and then use it for version control on his Windows machine. The GIT client chosen, usually is TortoiseGIT.

It turns out, that there are more than a few steps required to get this working correctly and I could not find a good first search result to get it working. I had to jump across various articles before I could stitch my process together. Here I have consolidated the steps in the hope that it would help other too.

This tutorial might also fix some errors which you might be getting such as the dreaded permission denied (publickey) or Permission Denied errors while committing. 
e.g.:
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights

and the repository exists.

git did not exit cleanly (exit code 128)


I am writing this on Windows 8, but this would apply to Windows 7 too.

  1. Begin by installing Putty on your Windows machine. Remember to install the complete installer, provided under the heading "Windows installer for everything except PuTTYtel". You can get it from here
  2. This will usually install the tool at c:\Program Files (x86)\PuTTY if you have proceeded with default settings.
  3. Next, run PuTTYgen to generate the Private ad Public SSH keys which we will require for this process. Select "SSH-2 RSA", and hit 'Generate'. Move the mouse in the blank area to generate the required keys.
  4. Once the tool has generated the keys, preferably provide a 'Key passphrase'. This is just a password to better protect your private key. Now use the buttons provided to save the Private and Public keys in some safe folder for future reference. Leave the PuTTYgen window open for now as we will need it a bit later again.
  5. Now run Pageant from Windows. Click on 'Add Keys', and provide it the private key file you had saved in the above step. Hit 'Close'
  6. Now from the already open PuTTYgen window, copy the text inside the box titled "Public key for pasting into Open SSH authorized_key file”"

  7. Now, we need to tell BitBucket about these new keys too. So open your BitBucket account and click 'Manage Account' 
  8. Click on 'SSH Keys' on the left hand menu. Click on the 'Add Key'. Here, paste the key which you copied from the step 6. above. Click on 'Add Key' to save the key.
  9. Finally, when we install TortoiseGIT, then by default it uses ssh.exe. Change it to use plink.exe. For this, in the folder on your computer which has the repository, right click and open TortoiseGIT settings. Under 'Network', provide the path to your plink file, which got installed when you had installed Putty.
  10. While you are in the setting, also check that under 'Git' > 'Remote', click on 'origin', and then the url provided is the one you got from BitBucket. Note that from Bitbucket you need to get the SSH url and not the HTTPS url. I also provided my private key on this page, but not really sure if that is mandatory.

*Phew!* That's quite a long list of steps to get this working, but once done, hopefully your TortoiseGIT will work super smoothly, not asking for authentication every now and then, and pushing your commits as intended.

Do leave a comment if this helped you too!