<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ferry Djaja on Medium]]></title>
        <description><![CDATA[Stories by Ferry Djaja on Medium]]></description>
        <link>https://medium.com/@ferrygunawan?source=rss-e0c3772a9b36------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*bDLCbZQUiXR6GiUSSzHMvA.png</url>
            <title>Stories by Ferry Djaja on Medium</title>
            <link>https://medium.com/@ferrygunawan?source=rss-e0c3772a9b36------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 11:20:26 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ferrygunawan/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Raspberry Pi 4 Google Duo Auto Answer Incoming Calls]]></title>
            <link>https://medium.com/@ferrygunawan/raspberry-pi-4-google-duo-auto-answer-incoming-calls-1afb8566bab9?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/1afb8566bab9</guid>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Tue, 03 Mar 2020 09:11:33 GMT</pubDate>
            <atom:updated>2020-03-03T09:11:33.970Z</atom:updated>
            <content:encoded><![CDATA[<p>Make Google Duo auto answer incoming calls with Raspberry Pi 4.</p><h3>Get Raspberry Pi with Ubuntu</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*okFhpmycA3uxJefly0AL1Q.png" /></figure><ul><li>Get <a href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/">Raspberry Pi 4</a> with 4 GB version.</li><li>Go to <a href="https://ubuntu.com/download/raspberry-pi">https://ubuntu.com/download/raspberry-pi</a> and install Ubuntu 18.04.4 LTS 32 bit version.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*R2GoSzrxQObzGgDN9rhlVw.png" /></figure><p>Install Ubuntu desktop:</p><pre>sudo apt-get update<br>sudo apt-get upgrade<br>sudo apt-get install ubuntu-desktop</pre><p>Edit <strong>/boot/firmware/usercfg.txt</strong></p><pre>nano /boot/firmware/usercfg.txt</pre><p>Insert the following content to force the Rpi to use HDMI output.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*fj0k2_gtE8eW0-vmXl7Jww.png" /></figure><p>Reboot the server.</p><h3><strong>Enable screen sharing for VNC</strong></h3><ul><li>Go to <strong>Settings </strong>and click <strong>Sharing</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*BrnIx8JFtGwxwwl-sbFzZA.png" /></figure><ul><li>Click on <strong>Screen Sharing</strong> and enable it.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/330/1*7jyalMawgzKlq30WXKmolw.png" /></figure><ul><li>Enable <strong>Remote Login</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/416/1*MraGbI6Z-q5lK66rhhYwEQ.png" /></figure><ul><li>Run the following command to disable the encryption. This feature creates problems for Windows machine while connecting.</li></ul><pre>sudo gsettings set org.gnome.Vino require-encryption false</pre><ul><li>Download the VNC Viewer from <strong>RealVNC</strong>: <a href="https://www.realvnc.com/en/connect/download/viewer/">https://www.realvnc.com/en/connect/download/viewer/</a></li><li>Create a new connection.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/473/1*evaoUHkk9eDFpYwpPRmUsA.png" /></figure><ul><li>Enter the Rpi IP address on VNC Server and unchecked the options for the Security Encryption. Click OK to save.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/920/1*8qDg_30jBtuOFhEjbs9z4A.png" /></figure><h3><strong>OpenCV 4</strong></h3><p>Install <strong>OpenCV 4</strong> from this guide: <a href="https://www.pyimagesearch.com/2018/08/15/how-to-install-opencv-4-on-ubuntu/">https://www.pyimagesearch.com/2018/08/15/how-to-install-opencv-4-on-ubuntu/</a></p><p>Noted that OpenCV installed on the virtual environment <strong>cv</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*hnNc_kTqbKWe0SMq.jpg" /></figure><h3><strong>Install the OCR Pytesseract and other required libraries</strong></h3><p>Install the OCR Pytesseract and other libraries on the virtual environment <strong>cv</strong>. Make sure you are installing from the virtual environment <strong>cv </strong>since we are installing the OpenCV in this environment.</p><pre>workon cv</pre><pre>pip install vext</pre><pre>pip install vext.gi</pre><pre>pip install PyUserInput</pre><pre>pip install pillow</pre><pre>pip install pytesseract</pre><pre>sudo apt-get install tesseract-ocr</pre><h3><strong>Install Chromium Web Browser</strong></h3><p>Run the following command to install the Chromium Web Browser:</p><pre>sudo apt install chromium-browser</pre><p>Open the browser and go to Google Duo site: <a href="https://duo.google.com/">https://duo.google.com</a>. Sign in and install the app on the browser.</p><p>Run the Chromium browser in kiosk mode:</p><pre>chromium-browser — kiosk — noerrors — disable-session-crashed-bubble — disable-infobars — disable-restore-session-state <a href="https://duo.google.com/">https://duo.google.com/</a></pre><h3>Map the Mouse Position</h3><p>We need to perform the OCR on the are highlighted in yellow and also to get the mouse cursor location on the “<strong>Accept</strong>” button.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_MR2cuYXDnsZ9VFmDRoxTw.png" /></figure><p>Update the Python code with the coordinate values.</p><h3><strong>Make it Auto Run</strong></h3><p>Create shell script <strong>googleduoauto.sh</strong> with the following content:</p><pre>#!/bin/bash<br>cd /home/ubuntu<br>source ~/.bashrc<br>workon cv<br>python /home/ubuntu/googleduo.py</pre><p>Create the entries for Chromium auto-start in kiosk mode and GoogleDuo shell script in <strong>Startup Applications Preferences</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/617/1*vWMDswQr291ndXp6GBIWqA.png" /></figure><p>Source code:</p><p><a href="https://github.com/ferrygun/GoogleDuoBot">https://github.com/ferrygun/GoogleDuoBot</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1afb8566bab9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Google Duo Answering Bot]]></title>
            <link>https://medium.com/@ferrygunawan/google-duo-answering-bot-ba54312ca26d?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/ba54312ca26d</guid>
            <category><![CDATA[google-duo]]></category>
            <category><![CDATA[bots]]></category>
            <category><![CDATA[raspberry-pi]]></category>
            <category><![CDATA[raspberry-pi-4]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Thu, 27 Feb 2020 05:58:58 GMT</pubDate>
            <atom:updated>2020-02-27T08:54:57.031Z</atom:updated>
            <content:encoded><![CDATA[<h3>Google Duo “Pick Up” Bot</h3><p>This is a simple hack with Google Duo to automatically pick up the calls from the recognized contacts.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5hRQd0CKAebFg2X4AcOZzg.png" /></figure><h4>Background</h4><p>The reason is because I need to call my mom without need for her to find the phone, pick up the call and answer it. And also her phone is not always with her and sometimes she has forgotten to charge the battery. I need to build something easy for her to handle.</p><h4><strong>How it works ?</strong></h4><p>Whenever the Google Duo receives the calls from the recognized contacts, it will answer the call, otherwise it will just ignore it.</p><h4><strong>What you need to have</strong></h4><p>We need to prepare the following stuff to make it work flawlessly:</p><ul><li>Ubuntu desktop Linux (I might port it to Raspberry Pi in the future).</li><li>Chromium Web Browser</li><li>Python 3 with OCR library Tesseract</li><li>Google Duo account</li></ul><p>I presume you have the Ubuntu desktop Linux installed on your virtual machine so let’s get started!!</p><p><strong>Install Chromium Web Browser and Auto Start After Boot</strong></p><p>Open the terminal window and run the following command:</p><pre><em>wget -qO — </em><a href="http://bintray.com/user/downloadSubjectPublicKey?username=bintray"><em>http://bintray.com/user/downloadSubjectPublicKey?username=bintray</em></a><em> | sudo apt-key add -</em></pre><pre><em>echo “deb </em><a href="http://dl.bintray.com/kusti8/chromium-rpi"><em>http://dl.bintray.com/kusti8/chromium-rpi</em></a><em> jessie main” | sudo tee -a /etc/apt/sources.list</em></pre><pre><em>sudo apt-get update</em></pre><pre><em>sudo apt-get install chromium-browser -y</em></pre><p>Now we need to set the chromium web browser to auto run on the startup.</p><p>Search for <strong>Startup Applications</strong> and create new startup entry.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/417/1*gcwOXEtuCWO1_T9CJANgFA.png" /></figure><p>Under command line, enter the following line:</p><pre>chromium-browser — kiosk — disable-session-crashed-bubble — disab-infobars — disable-restore-session-state <a href="https://duo.google.com/">https://duo.google.com/</a></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/728/1*uIZhekfYEpng05ozgvstdw.png" /></figure><h4><strong>Identify the Incoming Call (with the recognized contacts)</strong></h4><p>We need to solve the problem on how does the bot can identify the incoming calls with the valid contacts (otherwise it will be treat as a spam and ignore it).</p><p>To identify the incoming call, I am doing a simple hack by checking the pixel value on the predefined coordinate. The background color will turn darker if there is an incoming call.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4GiFcOpGWZas3jhoo7q7Rg.png" /></figure><p>The next step is to make sure the bot is only answering the predefined contacts. To answer this, I am using the OCR to scan the certain area and get the result.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*igzdJs5rHlD-ozKDkiFmEA.png" /></figure><p>Install Python 3 with <a href="https://github.com/tesseract-ocr/tesseract">Tesseract</a>. You may refer to this <a href="https://www.pyimagesearch.com/2017/07/10/using-tesseract-ocr-python/">write up</a>. Also install other necessary libraries: cv2 and pymouse. All code is <a href="https://github.com/ferrygun/GoogleDuoBot">here</a>.</p><p>That’s all that we need and hopefully you can make it as well. Don’t forget to turn off the screen saver or screen lock.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FYUnMBcREbEg&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DYUnMBcREbEg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/8799cb0dd45fc863c20bb36e50902a22/href">https://medium.com/media/8799cb0dd45fc863c20bb36e50902a22/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ba54312ca26d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Adding WhatsApp Reminder in Your Google Calendar]]></title>
            <link>https://medium.com/@ferrygunawan/adding-whatsapp-reminder-in-your-google-calendar-432266e0ac85?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/432266e0ac85</guid>
            <category><![CDATA[whatsapp]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[google-apps-script]]></category>
            <category><![CDATA[google-calendar]]></category>
            <category><![CDATA[events]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Tue, 30 Apr 2019 12:00:32 GMT</pubDate>
            <atom:updated>2019-04-30T12:00:32.412Z</atom:updated>
            <content:encoded><![CDATA[<p>I would like to share a simple trick on how to add the WhatsApp message reminder in your Google Calendar. The reminders can be sent to the multiple registered numbers. You can create a family events calendar reminder where your family members can be notified via WhatsApp.</p><p>Let’s get started !!</p><h4><strong>Setup Twilio WhatsApp Sandbox</strong></h4><ul><li>Create <a href="https://www.twilio.com/">Twilio</a> account and write down the <strong>Twilio Account SID</strong> and <strong>Auth. Token</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WTUGuH5aTnXIBc9F-vSOHg.png" /></figure><ul><li>Register your mobile number in Twilio Sandbox for WhatsApp.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nFM2VZ7PI0KnCW6MSH-Rqw.png" /></figure><p>That’s all the required setup in Twilio.</p><h4>Google Sheets Setup</h4><ul><li>Create <a href="https://www.google.com/sheets/about/">Google Sheets</a> account and create a new spreadsheet “WAReminders”</li><li>Add two sheets: <strong>Twilio <br></strong>Under Twilio sheet, enter the <strong>Twilio SID </strong>and <strong>Token </strong>information as shown in the below screenshot</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*BAPRIK5RGAFd_-wxed1gvw.png" /><figcaption><strong>Twilio </strong>Sheet</figcaption></figure><ul><li>And <strong>Contact<br></strong>Under Contact sheet, populate the cell number with format &lt;country code&gt;&lt;cell number&gt;, for example: <em>+6597123456</em>. The cell number is the registered number in Twilio WhatsApp Sandbox.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/680/1*IlY0YlTDSz6K0m7Yt3AFBQ.png" /><figcaption><strong>Contact </strong>Sheet</figcaption></figure><ul><li>Create Google Apps script Code.gs and replace the content with the source code in my <a href="https://github.com/ferrygun/WAGoogleCalendarReminders">Git</a></li><li>Basically the macro will get the calendar event title and check if title suffix ends with “~!#”</li><li>If yes, send the WhatsApp message to the registered number and update the title with “~!#”</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/865/1*AGK-71gOd30dYmTZ1ila1Q.png" /><figcaption>Macro</figcaption></figure><ul><li>Add the trigger and let the script runs every 5 minutes</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/588/1*5C6H_o1Uveauo0StjfeoRw.png" /><figcaption>Run the script every 5 minutes</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Jow-fEJEf10LvYs2MzCxcA.png" /></figure><h4>Testing!</h4><ul><li>Add an event in your Google Calendar</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F9tksYLVGqswkmQ0KIrqJg.png" /></figure><ul><li>Check your WhatsApp if you are getting any message from Twilio</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*fo3gozU0-pP_F_KxVoKJLA.png" /></figure><h4>Whats Next ?</h4><p>Adding a WhatsApp reminder is just one of the option. We can add a display reminder for example turning on and off the LED light.</p><p>That’s all about it and I hope it is beneficial for you with this simple trick!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=432266e0ac85" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build Android SAP Fiori OCR Scanner with SAP Web IDE and Anyline OCR SDK]]></title>
            <link>https://medium.com/@ferrygunawan/build-android-sap-fiori-ocr-scanner-with-sap-web-ide-and-anyline-ocr-sdk-f9bccb8e15ff?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/f9bccb8e15ff</guid>
            <category><![CDATA[sap]]></category>
            <category><![CDATA[sap-web-ide]]></category>
            <category><![CDATA[sapui5]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[ocr]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Sat, 05 Jan 2019 01:06:40 GMT</pubDate>
            <atom:updated>2019-01-09T11:25:12.920Z</atom:updated>
            <content:encoded><![CDATA[<p>I would like to share how easy to build the Android SAP Fiori OCR Scanner to scan the barcode label and text.</p><p>Here are the screenshots of the final app that we are going to build.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O8QSpkOl7rrDL9O0rIU_Lw.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bK8bnstXIY1hvNI1HzwzNA.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xF6w-GC580iz3vLW3_YRxA.jpeg" /></figure><h4><strong>Configuration &amp; Installation</strong></h4><p>We need to configure &amp; install the following software.</p><ul><li>SAP Mobile Platform SDK</li><li>SAP Web IDE Full Stack with HAT enabled</li><li>SAP HAT Local Installation</li><li>Anyline Cordova SDK</li></ul><h4>SAP Mobile Platform SDK</h4><p>Download and install SAP Mobile Platform SDK from <a href="https://www.sap.com/sea/developer/trials-downloads/additional-downloads/mobile-platform-sdk-free-download-13098.html">https://www.sap.com/sea/developer/trials-downloads/additional-downloads/mobile-platform-sdk-free-download-13098.html</a></p><p>Install the following components. The version in the bracket is the version that I am currently using and is working perfectly.</p><ul><li>Oracle Java (1.8.0)</li><li>Android SDK</li><li>Android Studio (3.0.1)</li><li>Cordova (6.5.0)</li><li>Kapsel SDK (3.16.0)</li><li>Ant (1.10.5)</li></ul><p>Set the following environment variables: ANT_HOME, JAVA_HOME and KAPSEL_HOME.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/619/1*ppy_PSB7mC8M5i3Nt4fw-A.png" /></figure><h4>SAP Web IDE Full Stack with HAT enabled</h4><p>Logon to SAP Cloud Platform Cockpit and enable the SAP Web IDE Full Stack</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TaCRDSIvPr_63wiM7Kbm8g.png" /></figure><p>Then go to service.</p><p>Click Preferences &gt; Features (Extensions) and search for Hybrid App Toolkit.</p><p>Enable and save it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LtrqLByv_40ccXg339TTNQ.png" /></figure><p>You will see the Hybrid App Toolkit.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NFVJoWjcTuHfu6f85ymP1Q.png" /></figure><p>Even though this feature has reached the end of maintenance, I can still use this feature to build the awesome apps and I find it easier.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/844/1*JTl9LtDcTjdKrCtKqzKjIw.png" /></figure><p>Next step is to install the HAT locally on your computer.</p><h4>SAP HAT Local Installation</h4><p>Download the HAT from this link: <a href="https://www.sap.com/india/developer/trials-downloads/additional-downloads/hybrid-app-toolkit-add-on-13586.html">https://www.sap.com/india/developer/trials-downloads/additional-downloads/hybrid-app-toolkit-add-on-13586.html</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5dEAVti1LSU3kjdRcvd2Ng.png" /></figure><p>I downloaded version 1.29.7</p><p>Download the required components for HAT.</p><ul><li>NodeJS (8.9.4<em>)</em></li><li>Npm (5.6.0<em>)</em></li><li>Git (2.13.2)</li><li>Bower (1.8.4)</li></ul><p>Extract the HAT Add-on to your C:\ drive. For my case is C:\SAP_HAT_local-1.29.7</p><p>We need to modify the HAT Add-on setup script, otherwise you will get an error message (I think is the setup script is too old and not maintained anymore by SAP).</p><p>Open <strong>check_env.cmd </strong>at folder .\SAP_HAT_local-1.29.7\setup\scripts\win and change the NodeJS version major, minor and build at line 62–64.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/721/1*my3lRGglqD9O1Mi9msCYNw.png" /></figure><p>Change it according to your NodeJS version (for my case is 8.9.4):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/729/1*Fg_pEjy5cATD3OAiGvDLtQ.png" /></figure><p>Run the <strong>setup.cmd</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/471/1*OZb4VU36IEMrtszONlbaJQ.png" /></figure><p>If no error, the browser will be opened. Click <strong>Check All</strong> to start the installation.</p><p>Make sure there is no error on each step and status is passed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qIdsc5FfTT8W3bkopNpRtA.png" /></figure><p>When you at step <strong>2.Install Hybrid App Toolkit &gt; 3. Configure HAT Connector for SAP Web IDE</strong>, enter the SAP Web IDE Full Stack URL</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*82XTW5KyP6M5d_amJngRCQ.png" /></figure><p>At step <strong>5 Configure path for custom plugins</strong>, specify the folder where you want to put the Anyline SDK Cordova plugin (for my case is C:\SAP\Plugins). Later we will download this plugin.</p><p>Continue the installation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f8N_7f7QovK8hHhmWKkRUw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5-RC1Sm51nHKwutd4tR7xw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Uzev6leonXuvYUomlg1wqQ.png" /></figure><p>Check again to ensure there is no error and all steps are <strong><em>passed </em></strong>then close the browser.</p><p>Go to HAT Add-on folder installation and run the HAT server.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/446/1*fZlou9TLVaRJV5_IWUgJ1A.png" /></figure><p>Check if SAP Web IDE can communicate to the server. Go to Web IDE &gt; Hybrid Application Toolkit and test the connection. If no error, you will see the similar result as per the below screenshot.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bGoTiZqa9rgCt9Fmde6q9A.png" /></figure><h4>Anyline Cordova SDK</h4><p>Download Anyline Cordova SDK from <a href="https://github.com/Anyline/anyline-ocr-cordova-module">https://github.com/Anyline/anyline-ocr-cordova-module</a> and put it under C:\SAP\Plugins\Anyline. That’s it!.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/595/1*RuOt1UWKw6uV_xVZRDrKDg.png" /></figure><h4>Create SAPUI5 App</h4><p>On SAP Web IDE, create the SAPUI5 app <strong>Scanner</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*znWwkxNNqqgwj5ZScFn0wA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oVS5_aEfeIf4n3MnU2yQ_g.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tWHNheQ27tog3IW1fpctWg.png" /></figure><p>Click Finish to complete.</p><p>Go to Project Settings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/706/1*QfnVAhCVxa0wSSj9END1YQ.png" /></figure><p>Select Hybrid App Toolkit &gt; App Configuration &gt; Application</p><p>Enter the <strong>App Name</strong> and <strong>App Id.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UGObMilYR83Q1kgEWUboyQ.png" /></figure><p>Select Hybrid App Toolkit &gt; App Configuration &gt; Plugins &gt; Custom.</p><p>Select Local &gt; AnylineSDK</p><p>Click Save</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VcwmBQ6wwCwWmeSgr0brIg.png" /></figure><p>Click Deploy &gt; Prepare Hybrid Project</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/706/1*2jPG70SGS8kc-7BbpTo3QA.png" /></figure><p>You will see the progress on the console. One of the activity is to install the Anyline Cordova plugin locally.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p23b4_oopoGM982FNqCaQA.png" /></figure><p>Wait until the app has been successfully deployed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pQRVbl3oeqtalecww7uJug.png" /></figure><p>It will be saved at C:\Users\&lt;user&gt;\SAPHybrid\Scanner</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/604/1*sTTWHtE9b1P6oGwXqNitmg.png" /></figure><p>Open Android Studio and import the project at C:\Users\&lt;user&gt;\SAPHybrid\Scanner\hybrid\platforms\android</p><p>If you see this error message:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oY1UEICddlrWw48iNJkSeQ.png" /></figure><p>Open <strong>gradle-wrapper.properties</strong>, change <strong>distributionUrl</strong> to:</p><pre><strong>distributionUrl</strong>=<strong>https\://services.gradle.org/distributions/gradle-4.6-all.zip</strong></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/947/1*wX0QXVSOaYTc7fjiNnY58A.png" /></figure><p>Update <strong>buildscript </strong>and <strong>allprojects </strong>on build.gradle (Project level):</p><pre>buildscript {<br>    repositories {<br>        mavenCentral()<br>        google()<br>        jcenter()<br>    }<br><br>    <em>// Switch the Android Gradle plugin version requirement depending on the<br>    // installed version of Gradle. This dependency is documented at<br>    // http://tools.android.com/tech-docs/new-build-system/version-compatibility<br>    // and https://issues.apache.org/jira/browse/CB-8143<br>    </em>dependencies {<br>        classpath <strong>&#39;com.android.tools.build:gradle:3.2.1&#39;<br>    </strong>}<br>}<br><br><em>// Allow plugins to declare Maven dependencies via build-extras.gradle.<br></em>allprojects {<br>    repositories {<br>        mavenCentral();<br>        google()<br>        jcenter()<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dVfEjFjfKP649yojcvaAdQ.png" /></figure><p>Update <strong>dependencies</strong>:</p><pre>dependencies {<br>    compile fileTree(<strong>dir</strong>: <strong>&#39;libs&#39;</strong>, <strong>include</strong>: <strong>&#39;*.jar&#39;</strong>)<br>    <em>// SUB-PROJECT DEPENDENCIES START<br>    //debugCompile(project(path: &quot;CordovaLib&quot;, configuration: &quot;debug&quot;))<br>    //releaseCompile(project(path: &quot;CordovaLib&quot;, configuration: &quot;release&quot;))<br>    </em>compile project(<strong>&#39;:CordovaLib&#39;</strong>)<br>    <em>// SUB-PROJECT DEPENDENCIES END<br></em>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*79SaiBWXTO6dsHf2d6mu1g.png" /></figure><p>Remove <strong>uses-sdk </strong>tag<strong> </strong>on AndroidManifest.xml.</p><pre>&lt;<strong>uses-sdk android:minSdkVersion=&quot;16&quot; android:targetSdkVersion=&quot;25&quot; </strong>/&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ycrD2bfqFCZKGmKZGPzLew.png" /></figure><p>Also remove <strong>uses-sdk</strong> on AndroidManifest.xml at CordovaLib level:</p><pre>&lt;<strong>uses-sdk android:minSdkVersion=&quot;14&quot; </strong>/&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-KTOO7S-7199ilVIoBYXVg.png" /></figure><p>Try to rebuild again.</p><p>Now the build is success!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XWFGxiGwRh3dmAz1I0aM2w.png" /></figure><p>Now we need to update the <strong>Scanner.controller.js</strong> and <strong>Scanner.view.xml</strong>.</p><p>Get the code from Git below and update these two files:</p><p><a href="https://github.com/ferrygun/Scanner/blob/master/webapp/controller/Scanner.controller.js">https://github.com/ferrygun/Scanner/blob/master/webapp/controller/Scanner.controller.js</a></p><p><a href="https://github.com/ferrygun/Scanner/blob/master/webapp/view/Scanner.view.xml">https://github.com/ferrygun/Scanner/blob/master/webapp/view/Scanner.view.xml</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LKyb_lnsXQXYQJzVu7ZmLw.png" /></figure><p>Copy the asset folder as well. This is the list of available trained fonts that will be used to recognize the character in the scanning process. We are going to use only the <strong>Calibri.traineddata</strong> for this purpose. Feel free to experiment with other asset files if the scan result is poor.</p><p><a href="https://github.com/ferrygun/Scanner/tree/master/webapp/assets">https://github.com/ferrygun/Scanner/tree/master/webapp/assets</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/316/1*I6ZfAsPNFgCLq5FAEAAuoA.png" /></figure><p>Let’s take a look at the main function in <strong>Scanner.controller.js </strong>before we build the app. We need to define the Anyline OCR &amp; Barcode configuration.</p><p><strong>Anyline OCR config</strong>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3d71e5c792d51358c94499d505c48883/href">https://medium.com/media/3d71e5c792d51358c94499d505c48883/href</a></iframe><p><strong>Anyline Barcode config</strong>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dbc6feaea6f9bbe473e0409917cb9951/href">https://medium.com/media/dbc6feaea6f9bbe473e0409917cb9951/href</a></iframe><p>Create <strong>getBarcode()</strong> and <strong>getOCR() </strong>to initiate barcode label and OCR scan.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/649aad64ac87990fa88a0282a7e3822c/href">https://medium.com/media/649aad64ac87990fa88a0282a7e3822c/href</a></iframe><p>Now everything is setup and we will build and run the app !</p><p>The complete codes can be found here:</p><p><a href="https://github.com/ferrygun/Scanner">ferrygun/Scanner</a></p><p>Thanks for reading and let me know if you have any questions!</p><p>The same post has been published in SAP blog: <a href="https://blogs.sap.com/2019/01/08/create-text-recognition-ocr-app-with-google-ml-kit-and-sap-web-ide/">https://blogs.sap.com/2019/01/08/create-text-recognition-ocr-app-with-google-ml-kit-and-sap-web-ide/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9bccb8e15ff" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Google Android Vision Multi Tracker: Recognize Barcode and Text (OCR) At The Same Time]]></title>
            <link>https://medium.com/@ferrygunawan/google-android-vision-multi-tracker-recognize-barcode-and-text-ocr-at-the-same-time-bf94dcf31235?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/bf94dcf31235</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[barcode]]></category>
            <category><![CDATA[android-vision]]></category>
            <category><![CDATA[ocr]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Mon, 17 Dec 2018 08:59:58 GMT</pubDate>
            <atom:updated>2018-12-17T08:59:58.099Z</atom:updated>
            <content:encoded><![CDATA[<p>We will build a simple scanner app that will recognize barcode and text at the same time with Google Android Vision library.</p><p>Here is the sample screenshot of the app. On the left hand-side, the app will recognize the barcode and expiry date at the same. Once it recognizes, it will throw the result automatically.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/891/1*HH_OedbocykFz3vc8q1Cvw.png" /></figure><p>Let’s grab and modify the multi-detector tutorial from <a href="https://developers.google.com/vision/android/multi-tracker-tutorial">https://developers.google.com/vision/android/multi-tracker-tutorial</a>. We will remove the Face detector and add the text detector.</p><h4><strong>Creating a Text Detector</strong></h4><p>Create a text detector to track texts.</p><pre>TextRecognizer textRecognizer = <strong>new </strong>TextRecognizer.Builder(context).build();</pre><h4>Creating a MultiProcessor for Managing Detected Texts</h4><p>Create a text tracker factory, <strong>ocrTrackerFactory </strong>for each text.</p><pre>OcrTrackerFactory ocrTrackerFactory = <strong>new </strong>OcrTrackerFactory(<strong>mGraphicOverlay</strong>, <strong>this</strong>);<br>textRecognizer.setProcessor(<br>        <strong>new </strong>MultiProcessor.Builder&lt;&gt;(ocrTrackerFactory).build());</pre><p>Conceptually, this creates a portion of the detector processing pipeline which looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1wpCnvQ4bM5B6ghIyBz7yg.png" /></figure><p>This portion of the pipeline works as follows:</p><ol><li>The text detector detects texts and creates a collection of text instances.</li><li>A multi-processor instance keeps track of each text that is currently active. It uses a factory to create a new graphic tracker instance per text.</li><li>As texts are tracked across video frames, the multi-processor sends updates to the corresponding text tracker instances. In this case, text updates are simply the position and size of the text within the video frame.</li></ol><h4>Using a MultiDetector to Combine the Barcode and Text Detectors</h4><p>Modify the multi detector on MultiTrackerActivity.java to include text detector and remove the face detector.</p><pre>MultiDetector multiDetector = <strong>new </strong>MultiDetector.Builder()<br>        .add(barcodeDetector)<br>        .add(textRecognizer)<br>        .build();</pre><h4><strong>OCRTrackerFactory.java</strong></h4><p>Create <strong>OCRTrackerFactory.java</strong> with two <strong>OcrTrackerFactory </strong>and <strong>OcrGraphic </strong>classes.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4cca15a04379ce719819bd40e98782f3/href">https://medium.com/media/4cca15a04379ce719819bd40e98782f3/href</a></iframe><h4><strong>GraphicTracker.java</strong></h4><p>On <strong>onUpdate() </strong>method we need to create a logic to differentiate if the detection result is barcode or text.</p><p>If detection result is text (OCR), set the flag to true otherwise is false (barcode)</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/89fe8ab1b7fe90173ec67f8e77bebe5f/href">https://medium.com/media/89fe8ab1b7fe90173ec67f8e77bebe5f/href</a></iframe><p>On <strong>onBarcodeDetected()</strong> method in MultiTrackerActivity.java, get the detection result. If you notice on the barcode result, I only need to get the first barcode that has found:</p><pre>Barcode barcode = items.valueAt(0)</pre><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0baee2c9af6abe1db3be21513f62281d/href">https://medium.com/media/0baee2c9af6abe1db3be21513f62281d/href</a></iframe><h4><strong>Create a Thread to Get the Detected Barcode and Text</strong></h4><p>Create a thread <strong>Task() </strong>on MultiTrackerActivity.java that will loop every one second to get the barcode and text result. Once we got the barcode and text values, start a new activity, <strong>SendScannedBarcode()</strong>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bee3a2c7d0d35974b349784f80df5e39/href">https://medium.com/media/bee3a2c7d0d35974b349784f80df5e39/href</a></iframe><p>Here is the full source code: <a href="https://github.com/ferrygun/multi-tracker">https://github.com/ferrygun/multi-tracker</a></p><p>Enjoy !!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bf94dcf31235" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Blockchain NodeJS Server Monitoring]]></title>
            <link>https://medium.com/coinmonks/blockchain-nodejs-server-monitoring-69f0dd2772ab?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/69f0dd2772ab</guid>
            <category><![CDATA[hyperledger-fabric]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[blockchain]]></category>
            <category><![CDATA[hyperledger]]></category>
            <category><![CDATA[nodejs]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Mon, 10 Sep 2018 04:25:46 GMT</pubDate>
            <atom:updated>2020-09-01T13:08:59.662Z</atom:updated>
            <content:encoded><![CDATA[<p>I would like to walk through how to build a simple server monitoring with Blockchain. We will write a NodeJS client app that will submit the transaction to the Fabric with the server parameters like number of active memory, hardware model, number of installed CPU and RAM, server model and data center ID.</p><p>We need to have two machines running on Ubuntu. We will install NodeJS client and Hyperledger Fabric component on each machine.</p><p>The high-level architecture would be like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/927/1*Y5WLnFkZ7m0-YKxn_yWAqQ.png" /></figure><h3><strong>Hyperledger Fabric Server</strong></h3><p>Follow my below post to setting up the server. Install and configure Hyperledger Fabric on the first machine.</p><p><a href="https://medium.com/coinmonks/getting-started-with-hyperledger-composer-34cb7228d44c">Getting Started with Hyperledger Composer</a></p><p>You don’t need to install and configure the REST server. Take note the IP address of this machine.</p><h3><strong>NodeJS Client App</strong></h3><p>On the second machine, install the composer-client and composer-cli:</p><pre>npm install --save composer-client@0.20</pre><pre>npm install --save composer-admin@0.20</pre><p>We need to copy the admin@tutorial-network that we created on the Fabric side to the client side. Logon to the first machine and copy the admin@tutorial-network folder located <strong>$HOME/.composer/cards </strong>and <strong>$HOME/.composer/client-data.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/755/1*blRr_HJBu1CItrX6-N4prQ.png" /></figure><p>Logon to the client machine and paste those files to the client machine.</p><p>Open the <strong>connection.json</strong> from <strong>$HOME\.composer\cards\admin@tutorial-network</strong> and update the connection string from localhost to the server IP address (for my case is 192.168.0.109):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/84e77ec18e8d73b46459c3c1c4841516/href">https://medium.com/media/84e77ec18e8d73b46459c3c1c4841516/href</a></iframe><h4>Execute the Script</h4><p>We will execute the NodeJS app on the client side:</p><ul><li>To create the participant and asset, execute:</li></ul><pre>node cli serverregistry bootstrap</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/945/1*nyEN07XBE_Wa7c2aCzfYVQ.png" /></figure><p>The script will populate the participant and asset with the predefined value:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*IN8bDWsJ_XYruveSCM369g.png" /><figcaption>Participant Registry</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1016/1*0wZLjONdeYqNyf6LeNLI2g.png" /><figcaption>Asset Registry</figcaption></figure><ul><li>To get the list of the asset, execute:</li></ul><pre>node cli serverregistry list</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/882/1*QtWiywmXbYCfH3Yvg1V6hw.png" /></figure><p>As you can see in the above screenshot, the value of Active_Memory, HW_Model, etc is still empty because we haven’t submitted the transaction.</p><ul><li>To submit the transaction, execute:</li></ul><pre>node cli serverregistry submit 64 &quot;Model A&quot; 8 4 &quot;Server A&quot; ADM</pre><p>with parameters:</p><p>· <strong>Active_Memory</strong>: 64</p><p>· <strong>HW_Model</strong>: Model A</p><p>· <strong>Installed_CPUs</strong>: 8</p><p>· <strong>Installed_RAM</strong>: 4</p><p>· <strong>Server_Model</strong>: Server A</p><p>· <strong>datacenterid</strong>: ADM</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/869/1*bxl3YPuov3pfqbBWLI5s5A.png" /></figure><p>Try to execute the previous command: node cli serverregistry listand you will see the transaction has been populated:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/871/1*edC-0ZrkZH9JeiIwB7ZZmA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1021/1*TtJR70WcbSo3qXc1tQz9yA.png" /></figure><ul><li>To listen to the event, execute:</li></ul><pre>node cli serverregistry listen</pre><p>Event will be emitted once you submit the transaction. You will see the console log printed out.</p><p>All codes can be found on my Git repo: <a href="https://github.com/ferrygun/NodeJS-Blockchain">https://github.com/ferrygun/NodeJS-Blockchain</a></p><blockquote><a href="https://coincodecap.com/?utm_source=coinmonks">Get Best Software Deals Directly In Your Inbox</a></blockquote><figure><a href="https://coincodecap.com/?utm_source=coinmonks"><img alt="" src="https://cdn-images-1.medium.com/max/584/0*OJ-qb5G6i863msBB.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=69f0dd2772ab" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coinmonks/blockchain-nodejs-server-monitoring-69f0dd2772ab">Blockchain NodeJS Server Monitoring</a> was originally published in <a href="https://medium.com/coinmonks">Coinmonks</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hyperledger Composer Troubleshooting]]></title>
            <link>https://medium.com/@ferrygunawan/hyperledger-composer-troubleshooting-2c6eeb9fd214?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/2c6eeb9fd214</guid>
            <category><![CDATA[hyperledger]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[hyperledger-fabric]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Fri, 07 Sep 2018 00:57:37 GMT</pubDate>
            <atom:updated>2018-09-07T00:57:37.414Z</atom:updated>
            <content:encoded><![CDATA[<p>This is a live document that I will be keep updating to troubleshoot the Hyperledger Composer.</p><p><strong>Problem statement:</strong></p><p>When you click “Connect now”, you can’t connect the network</p><p><strong>Error message:</strong></p><p><em>Error: Error trying to ping. Error: Failed to connect before the deadline</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RrXeXPB5gJyfhdeSyN6sLQ.png" /></figure><p><strong>Resolution:</strong></p><ul><li>I presume you already have the business network archive (.bna) file and business network card (.card) in your folder. If not, please follow this link to generate those files: <a href="https://hyperledger.github.io/composer/latest/tutorials/developer-tutorial.html">https://hyperledger.github.io/composer/latest/tutorials/developer-tutorial.html</a></li><li>Stop and tear down the fabric:</li></ul><pre>~/fabric-dev-servers/stopFabric.sh</pre><pre>~/fabric-dev-servers/teardownFabric.sh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/564/1*MKSpgAQ8HVrkoisFyJ9Sxg.png" /></figure><ul><li>Remove the previous docker containers:</li></ul><pre>docker kill $(docker ps -q)<br>docker rm $(docker ps -aq)<br>docker rmi $(docker images dev-* -q)</pre><ul><li>Start the Fabric and create the Peer Admin card:</li></ul><pre>~/fabric-dev-servers/startFabric.sh<br>~/fabric-dev-servers/createPeerAdminCard.sh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*V38JBbfg4wC8LClJikeYgQ.png" /></figure><ul><li>If you trying to ping now, you will get this message:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_tmVUwniaQNO4qxf2O-WfQ.png" /></figure><ul><li>Navigate to the folder where you kept the .bna and .card files.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-u33Fyj8GsmKiONInQ7wqg.png" /></figure><ul><li>Install the business network archive (.bna):</li></ul><pre>composer network install --card PeerAdmin@hlfv1 --archiveFile tutorial-network@0.0.1.bna</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*W2ocqbNQS3DUhW6SB9rmAA.png" /></figure><ul><li>Start the business network:</li></ul><pre>composer network start --networkName tutorial-network --networkVersion 0.0.1 --networkAdmin admin --networkAdminEnrollSecret adminpw --card PeerAdmin@hlfv1 --file networkadmin.card</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yO92OQOX-Kvnn6ElZY7-CA.png" /></figure><ul><li>Ping the network:</li></ul><pre>composer network ping --card admin@tutorial-network</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*laSDkAks0I_yUEpEflJGIQ.png" /></figure><ul><li>Now click “Connect now”, you will get the message “refreshing the connection to …”. And you are connected to the network now.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8vteZkDqKzEBmGGO4QC_vQ.png" /></figure><p>Hope that helps!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2c6eeb9fd214" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started with Hyperledger Composer]]></title>
            <link>https://medium.com/coinmonks/getting-started-with-hyperledger-composer-34cb7228d44c?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/34cb7228d44c</guid>
            <category><![CDATA[hyperledger-composer]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[hyperledger-fabric]]></category>
            <category><![CDATA[hyperledger]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Tue, 04 Sep 2018 04:02:00 GMT</pubDate>
            <atom:updated>2020-09-01T13:14:41.475Z</atom:updated>
            <content:encoded><![CDATA[<p>On the first post, I would like to run through the installation process of Hyperledger Composer on Ubuntu 16.0.4 LTS. On the part two, we will create a simple SAP Mobile App that consumer the REST API of Hyperledger Composer.</p><blockquote><a href="https://coincodecap.com/">Discover and review best Blockchain softwares</a></blockquote><h3><strong>What is Hyperledger Composer?</strong></h3><p>According to their website: Hyperledger Composer is a set of collaboration tools for building blockchain business networks that make it simple and fast for business owners and developers to create smart contracts and blockchain applications to solve business problems. Built with JavaScript, leveraging modern tools including node.js, npm, CLI and popular editors, Composer offers business-centric abstractions as well as sample apps with easy to test devops processes to create robust blockchain solutions that drive alignment across business requirements with technical development.</p><p><a href="https://www.hyperledger.org/projects/composer">https://www.hyperledger.org/projects/composer</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*HarF6pwo0JSa0RWi.png" /></figure><h3><strong>Hyperledger Composer Installation</strong></h3><p>At your home directory, install the prerequisites by running the following script:</p><pre>cd $HOME<br>curl -O -k <a href="https://hyperledger.github.io/composer/latest/prereqs-ubuntu.sh">https://hyperledger.github.io/composer/latest/prereqs-ubuntu.sh</a><br>chmod u+x prereqs-ubuntu.sh</pre><p>run the command to install the:</p><pre>sudo apt-get install -y software-properties-common</pre><p>Once it’s completed without any error, you will get this message:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/553/1*EJT5Y64NLeXFA8Zu16vd6g.png" /></figure><h4><strong>Install Required Components</strong></h4><pre>npm install -g composer-cli@0.20<br>npm install -g composer-rest-server@0.20<br>npm install -g generator-hyperledger-composer@0.20<br>npm install -g yo</pre><h4><strong>Install Playground</strong></h4><pre>npm install -g composer-playground@0.20</pre><h4><strong>Install Hyperledger Fabric</strong></h4><p>Create a directory fabric-dev-servers at your home directory.</p><pre>mkdir ~/fabric-dev-servers &amp;&amp; cd ~/fabric-dev-servers</pre><p>And run curl command to download the tool and unzip it.</p><pre>curl -O <a href="https://raw.githubusercontent.com/hyperledger/composer-tools/master/packages/fabric-dev-servers/fabric-dev-servers.tar.gz">https://raw.githubusercontent.com/hyperledger/composer-tools/master/packages/fabric-dev-servers/fabric-dev-servers.tar.gz</a></pre><pre>tar -xvf fabric-dev-servers.tar.gz</pre><h4><strong>Download the runtime:</strong></h4><pre>export FABRIC_VERSION=hlfv12<br>./downloadFabric.sh</pre><h4><strong>Running on the First Time</strong></h4><pre>cd ~/fabric-dev-servers<br> export FABRIC_VERSION=hlfv12<br> ./startFabric.sh<br> ./createPeerAdminCard.sh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/857/1*c30OC-_LfLff1ueYjm-5-Q.png" /></figure><p>To stop, run this command:</p><pre>~/fabric-dev-servers/stopFabric.sh</pre><h4><strong>Start the Playground</strong></h4><p>To start, run the following command:</p><pre>composer-playground</pre><p>It will open the browser automatically and redirect to <a href="http://localhost:8080/login">http://localhost:8080/login</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X9Is0z2ogFkDGJu1cRrB7A.png" /></figure><h3><strong>Create New Business Network with Command Line</strong></h3><p>Create a new folder at your home folder, name it (for example) <strong>blockchainDocker</strong>. Go to that folder and run this command:</p><pre>yo hyperledger-composer:businessnetwork</pre><p>Fill the Business network name: <strong>tutorial-network</strong>, Namespace: <strong>org.basic.server</strong> and the rest is up to you.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/841/1*Nn2eKEupTP1TcV8oYbdUtw.png" /></figure><p>Upon successful, you will see the new folder <strong>tutorial-network</strong> was created.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/648/1*RwIewhdknHhFX5qLTi91iQ.png" /></figure><p>Go to the folder <strong>tutorial-network/lib</strong> and update the <strong>logic.js</strong> with the following content:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cc78574be642f3625ac629ab034091c6/href">https://medium.com/media/cc78574be642f3625ac629ab034091c6/href</a></iframe><p>Update <strong>org.basic.server.cto </strong>in<strong> tutorial-network/models </strong>with the following content:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/06be44202fc40a2e41bd459fd68e01a0/href">https://medium.com/media/06be44202fc40a2e41bd459fd68e01a0/href</a></iframe><p>We will leave<strong> permissions.acl </strong>file as it is.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/59fb410a9ee66c46994eb969361ea14c/href">https://medium.com/media/59fb410a9ee66c46994eb969361ea14c/href</a></iframe><h3>Generate a Business Network Archive</h3><p>After we defined the business network, it must be packaged into a deployable business network archive (.bna) file. Go to the <strong>tutorial-network</strong> folder and run this command.</p><pre>composer archive create -t dir -n .</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/729/1*3tENI9T8794RW5atYhpiTg.png" /></figure><h3>Deploying Business Network Archive</h3><p>Run the following command to install the business network from t<strong>utorial-network</strong> directory:</p><pre>composer network install --card PeerAdmin@hlfv1 --archiveFile tutorial-network@0.0.1.bna</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vqCUJ8mYkKzCfUJDdQnN7Q.png" /></figure><p>To start the business network, run the following command:</p><pre>composer network start --networkName tutorial-network --networkVersion 0.0.1 --networkAdmin admin --networkAdminEnrollSecret adminpw --card PeerAdmin@hlfv1 --file networkadmin.card</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ulfiNyiG-Y8NUaRGFxSjvQ.png" /></figure><p>To import the network administrator identity as a usable business network card, run the following command:</p><pre>composer card import --file networkadmin.card</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FK5CRbtqDgWoxLyYu4mHKQ.png" /></figure><p>Once you have imported, you will see the card in the Playground: <a href="http://localhost:8080/login">http://localhost:8080/login</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/295/1*E6fMStB2yGaz2GzXcQwbXQ.png" /></figure><p>To check that the business network has been deployed successfully, run the following command to ping the network:</p><pre>composer network ping --card admin@tutorial-network</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LZB_kz6KNbJGgaPtUmGKxQ.png" /></figure><h4><strong>Test the Network</strong></h4><p>We are going to test the network by populating the prerequisite information for the asset <strong>DataCenterId</strong>. The Participant <strong>Personnel</strong> in this example is not being used. Once we have the DataCenterID populated, we can submit the transaction against the particular DataCenterID with the server parameters like how many memory installed, how many CPU installed, etc.</p><ul><li>Go to <a href="http://localhost:8080/login">http://localhost:8080/login</a></li><li>Click <strong>Connect now</strong> to connect to the network</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/287/1*J6WlWZOxM616aBkhFmM0Zw.png" /></figure><ul><li>Go to <strong>Test</strong> tab.</li><li>Populate the prerequisite information. Under <strong>Participants</strong>, select <strong>Personnel</strong> and click <strong>New Participant</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/566/1*S3geNCzRIbKixkyHy9M2Aw.png" /></figure><ul><li>Once you created, you will see the registry entry under <strong>Participants</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U-x2qz2PJmVpBMh6bxnXyQ.png" /></figure><ul><li>Create the Asset <strong>DataCenterId </strong>(for example <strong>DC1</strong>).</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/573/1*lDc3cWcVrjcGBU15P4zGow.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iBr-DKl8sPcfeOzf3hUirQ.png" /></figure><ul><li>Submit a transaction to a particular Data Center, for this example is the Data Center Id <strong>DC1</strong> that we just created.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/570/1*1qsCXNClfSxuNhJL2b3RYA.png" /></figure><ul><li>If we submit the transaction to the Data Center Id which is not exist, it will throw an error message. In this example below, the Data Center Id <strong>DC2</strong> has not been defined and we will get an error message.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/575/1*nlEsJZfBC_7gkVaMZLe3kQ.png" /></figure><ul><li>Once you have successfully submitted the transaction, you will see the server parameter information is populated under the Data Center Id you have submitted (in this case is <strong>DC1</strong>).</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T_lVOOS1X01hU764PwNXuQ.png" /></figure><ul><li>To see the log of transactions, select <strong>All Transactions. </strong>Click <strong>view record</strong> to see all the detail log transactions.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5Tib-slx7Dr59Nv-sCLu3A.png" /></figure><h4><strong>REST Server</strong></h4><p>The last thing that we want to build is the REST server. With this, we can expose the Assets, Participants and Transactions that we have created so it can be consumed with the client app like web or mobile app.</p><p>We will create a docker container for this purpose with the following steps:</p><ul><li>Install the LoopBack connector for MongoDB:</li></ul><pre>npm install -g loopback-connector-mongodb</pre><ul><li>Make sure you can ping the <strong>tutorial-network</strong>. Run this command:</li></ul><pre>composer network ping -c admin@tutorial-network</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K504bL2kH_TlhaCFP1e_sQ.png" /></figure><ul><li>Start an instance of docker called <strong>mongo</strong>. This instance will be used to persist all information regarding authenticated users and their wallets for the REST server.</li></ul><pre>docker run -d --name mongo --network composer_default -p 27017:27017 mongo</pre><ul><li>Create a new file called <strong>Dockerfile</strong> under new folder with the following contents:</li></ul><pre>FROM hyperledger/composer-rest-server<br>RUN npm install --production loopback-connector-mongodb passport-github &amp;&amp; \<br>    npm cache clean --force &amp;&amp; \<br>    ln -s node_modules .node_modules</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/384/1*qc9JWfr0gXnJm1zVAnNwzw.png" /></figure><ul><li>Run this command:</li></ul><pre>docker build -t myorg/my-composer-rest-server .</pre><ul><li>Create a new file <strong>envvars.txt </strong>on the same folder with this content:</li></ul><pre>COMPOSER_CARD=admin@tutorial-network<br>COMPOSER_NAMESPACES=never<br>COMPOSER_AUTHENTICATION=true<br>COMPOSER_MULTIUSER=false<br>COMPOSER_PROVIDERS=&#39;{<br>    &quot;github&quot;: {<br>        &quot;provider&quot;: &quot;github&quot;,<br>        &quot;module&quot;: &quot;passport-github&quot;,<br>        &quot;clientID&quot;: &quot;REPLACE_WITH_CLIENT_ID&quot;,<br>        &quot;clientSecret&quot;: &quot;REPLACE_WITH_CLIENT_SECRET&quot;,<br>        &quot;authPath&quot;: &quot;/auth/github&quot;,<br>        &quot;callbackURL&quot;: &quot;/auth/github/callback&quot;,<br>        &quot;successRedirect&quot;: &quot;/&quot;,<br>        &quot;failureRedirect&quot;: &quot;/&quot;<br>    }<br>}&#39;<br>COMPOSER_DATASOURCES=&#39;{<br>    &quot;db&quot;: {<br>        &quot;name&quot;: &quot;db&quot;,<br>        &quot;connector&quot;: &quot;mongodb&quot;,<br>        &quot;host&quot;: &quot;mongo&quot;<br>    }<br>}&#39;</pre><ul><li>Run this command to load it to the environment variable:</li></ul><pre>source envvars.txt</pre><ul><li>We need to update the localhost string on the <strong>~/.composer/cards/admin@tutorial-network/connection.json</strong>.</li></ul><pre>sed -e ‘s/localhost:7051/peer0.org1.example.com:7051/’ -e ‘s/localhost:7053/peer0.org1.example.com:7053/’ -e ‘s/localhost:7054/ca.org1.example.com:7054/’ -e ‘s/localhost:7050/orderer.example.com:7050/’ &lt; $HOME/.composer/cards/admin@tutorial-network/connection.json &gt; /tmp/connection.json &amp;&amp; cp -p /tmp/connection.json $HOME/.composer/cards/admin@tutorial-network/</pre><ul><li>run the docker:</li></ul><pre>docker run \<br>    -d \<br>    -e COMPOSER_CARD=${COMPOSER_CARD} \<br>    -e COMPOSER_NAMESPACES=${COMPOSER_NAMESPACES} \<br>    -e COMPOSER_AUTHENTICATION=${COMPOSER_AUTHENTICATION} \<br>    -e COMPOSER_MULTIUSER=${COMPOSER_MULTIUSER} \<br>    -e COMPOSER_PROVIDERS=&quot;${COMPOSER_PROVIDERS}&quot; \<br>    -e COMPOSER_DATASOURCES=&quot;${COMPOSER_DATASOURCES}&quot; \<br>    -v ~/.composer:/home/composer/.composer \<br>    --name rest \<br>    --network composer_default \<br>    -p 3000:3000 \<br>    myorg/my-composer-rest-server</pre><ul><li>Check if the server is running without error, you will see the message as per below screenshot.</li></ul><pre>docker logs -f rest</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eCDtdftOyIVkFvgDIseq5Q.png" /></figure><ul><li>Open the web browser and go to this URL: <a href="http://localhost:3000/auth/github">http://localhost:3000/auth/github</a></li><li>Click <strong>Authorize</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0Jv3qtG2thfANhtGw6dsOA.png" /></figure><ul><li>If no error, you will see the page below with the access token information.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vkO2Je_A8AF7rJf7iEWJqg.png" /></figure><ul><li>Select <strong>Server : A transaction named Server </strong>and click <strong>Post</strong>. Populate with the below data and click <strong>Try it out!</strong>.</li></ul><pre>{<br> “$class”: “org.basic.server.Server”,<br> “Active_Memory”: 4,<br> “HW_Model”: “Dell”,<br> “Installed_CPUs”: 2,<br> “Installed_RAM”: 4,<br> “Server_Model”: “Model A”,<br> “datacenterid”: “DC1”<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*76JoCfoIkJufrPO2xyGzlw.png" /></figure><ul><li>Now select <strong>Get </strong>and click <strong>Try it out!</strong>. You will see the data that you have posted.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VTHNl4urC82xdMWkTu0_og.png" /></figure><p>Stay tuned for part 2 where we will build a SAP mobile app (SAPUI5) that consumed the REST API. Thanks for reading my post.</p><blockquote><a href="https://coincodecap.com/?utm_source=coinmonks">Get Best Software Deals Directly In Your Inbox</a></blockquote><figure><a href="https://coincodecap.com/?utm_source=coinmonks"><img alt="" src="https://cdn-images-1.medium.com/max/584/0*OJ-qb5G6i863msBB.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=34cb7228d44c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/coinmonks/getting-started-with-hyperledger-composer-34cb7228d44c">Getting Started with Hyperledger Composer</a> was originally published in <a href="https://medium.com/coinmonks">Coinmonks</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Make Google Assistant App to Check Train Arrival Times with Dialogflow]]></title>
            <link>https://blog.chatbotslife.com/make-google-assistant-app-to-check-train-arrival-times-with-dialogflow-71cf02103e8?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/71cf02103e8</guid>
            <category><![CDATA[bots]]></category>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[dialogflow]]></category>
            <category><![CDATA[google-assistant]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Tue, 26 Jun 2018 09:49:22 GMT</pubDate>
            <atom:updated>2018-07-05T13:16:37.491Z</atom:updated>
            <content:encoded><![CDATA[<p>Let’s make an Google Assistant <a href="https://chatbotslife.com/">chatbot</a> app to check the train arrival times for SMRT (Singapore MRT train operator).</p><p>I have made one 👌 and it is available for public (you can try it now) from your phone or Google Home.</p><p>If I can make it, I hope you also can do it, so let’s get started!!</p><p><a href="https://www.facebook.com/TrainOnDemand/">https://www.facebook.com/TrainOnDemand/</a></p><p><a href="https://www.facebook.com/TrainOnDemand/">Train On Demand</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/376/1*v-TmlCFs0TvnB8OZFbotCw.png" /><figcaption>Train OnDemand</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qnYq0S3DXo1qnhYe" /><figcaption>SMRTConnect</figcaption></figure><h3>See What’s Inside</h3><p>The train arrival times information is based on the <strong>SMRTConnect</strong> App.</p><p><a href="https://play.google.com/store/apps/details?id=sg.com.smrt.smrtconnect&amp;hl=en_IN">SMRTConnect - Apps on Google Play</a></p><p>Download the latest apk (version 3.1.3) from <a href="https://apkpure.com/smrtconnect/sg.com.smrt.smrtconnect">https://apkpure.com/smrtconnect/sg.com.smrt.smrtconnect</a></p><p>We will analyze how it works and where to get the necessary information for our app. Download <a href="https://github.com/skylot/jadx">jadx </a>and we will use this tool to analyze the code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/949/1*ZDUvpSmOWYor1Dt-l5lKQw.png" /><figcaption>jadx GUI</figcaption></figure><p>Let’s take a look at the <strong>asset</strong> folder and check if we can find anything useful.</p><p>I found this <strong>app.properties</strong> under <strong>asset</strong> folder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/514/1*NKFfDwc8cBHPOXm0ml1kdQ.png" /></figure><p>The app is using <strong>Hawk</strong> authentication mechanism.</p><p>Citing from <a href="https://github.com/hueniverse/hawk">https://github.com/hueniverse/hawk</a>: <br><em>Hawk is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with partial cryptographic verification of the request and response, covering the HTTP method, request URI, host, and optionally the request payload</em>.</p><figure><a href="https://www.eventbrite.com/e/chatbot-conference-tickets-45884424549?utm-medium=discovery&amp;utm-campaign=social&amp;utm-content=attendeeshare&amp;aff=escb&amp;utm-source=cp&amp;utm-term=listing"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oyftTzPL9qaCYc8z2EbcHg.png" /></a></figure><p>From the properties file we can see the server URL, hawk id and key. We will be using the following information:</p><pre><strong>wshelper.server-prefix2=</strong><a href="https://connectv3.smrt.wwprojects.com/smrt/"><strong>https://connectv3.smrt.wwprojects.com/smrt/</strong></a><strong><br>wshelper.hawk-id2=ww-connectv3-android<br>wshelper.hawk-key2=h42325aqx6krj5z2uzm5e8wwqr2wchk5xq704n1e</strong></pre><p>Get the <strong>hawk-key2</strong> and let’s name it as <strong>key</strong>. The below code is NodeJS syntax. We will create the app in NodeJS.</p><pre><strong>let key = &#39;h42325aqx6krj5z2uzm5e8wwqr2wchk5xq704n1e&#39;;</strong></pre><p>From this point, we need to trace in the codes where this key is being used.</p><h3>Top 3 Bot Tutorials</h3><blockquote><a href="https://chatbotslife.com/write-a-serverless-slack-chat-bot-using-aws-e2d2432c380e">1. Write a serverless Slack chat bot using AWS</a></blockquote><blockquote><a href="https://chatbotslife.com/chatbot-using-django-rest-framework-api-ai-slack-part-1-3-69c7e38b7b1e">2. Chatbot using django rest framework + api.ai + slack</a></blockquote><blockquote><a href="https://chatbotslife.com/building-a-chatbot-with-watson-9f286bd6e3d1">3. Building a ChatBot with Watson</a></blockquote><p>Take a look at this piece of code in <strong>com.smrt.smrtconnect.Helpers.wsHelper.WSHelper.java </strong>under method <strong>getAuthorizationHeader</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KLfcsa1X-FCqes88DCopoA.png" /></figure><p>I found another important key to calculate the MAC with the hash algorithm sha256<br>Let’s name this key as <strong>hashq</strong>:</p><pre><strong>let hashq = &#39;q/t+NNAkQZNlq/aAD6PlexImwQTxwgT2MahfTa9XRLA=&#39;;</strong></pre><p>This method <strong>getAuthorizationHeader </strong>is very important and as our reference to build the app.</p><p>Let’s go a little deeper. We need to find other methods that are calling <strong>getAuthorizationHeader</strong>.</p><p>And I found <strong>refreshTokens</strong> method under <strong>com.smrt.smrtconnect.Helpers.CDNHelper.java.</strong> We will be using this token to refresh the updated station information.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/930/1*egXvKDFCSOxL7Vepw2gB9w.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3f93b7de426c6c6cda3e189d19b85348/href">https://medium.com/media/3f93b7de426c6c6cda3e189d19b85348/href</a></iframe><p>Output token from the above code:</p><pre>{“results”:{“<a href="http://connect-v3-cdn.smrt.wwprojects.com/">http://connect-v3-cdn.smrt.wwprojects.com/</a>&quot;:&quot;?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2Nvbm5lY3QtdjMtY2RuLnNtcnQud3dwcm9qZWN0cy5jb20vKiIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTUzMDAwOTQ3NX19fV19&amp;Signature=hvfLverTCMgEDGW6zzFaVKm0PIVid0~jW9P1JH-S4BFivkHJEeyCxo9VGUFWuxu3hj1fXF~IbphdM~bgF3X6LwiJ~u3eNY7cEuxPrgItti6OXlszjotgk8aJL7pqD7BCi6Y2PTcfXT26RAbVYn9uAGh6XL9uU2Y4I6sHGPJfvO6BB07UD4xj3D8JB6IuuyzjRV-ZI--~eeFzYRWf8k02bXEmwf7ZDDvUJS5uPfzvKBHJX~qDIoPjWu~Q4wVP8Gsj0dHQpGtNExy87QhSHC29bjxKW1hvXBPlpvvIPkp6Mf3i~nDcFo~lwYqIJ6LNiuRroSXi3zR8CrMKteqszhsSEQ__&amp;Key-Pair-Id=APKAIZHURKILCXZIMLUA&quot;}}</pre><p>From the given token, we will get the most updated station information from <strong>stations.json</strong>.</p><pre><strong>let path = &#39;/autoupdate_data/stations.json?Key-Pair-Id=&#39; + keypairid + &#39;&amp;Signature=&#39; + signature + &#39;&amp;Policy=&#39; + policy;</strong></pre><p>Apart from the above method, I am also using the <a href="https://medium.com/@ferrygunawan/debug-ssl-traffic-with-charles-proxy-872aedb228d">Charles Proxy</a> to analyze the network traffic. With that combination, it will be easier to trace the flow of the app and validate the responses.</p><h3><strong>Fun Part</strong></h3><p>With the above reference, we will build a simple NodeJS app to validate the response. Once it is successful, we will continue to build the app on Google Assistant.</p><h4>Generate the Authentication Header</h4><p>The Node app will generate the authentication header by calculating a timestamp, generating a nonce and constructing the normalized request string (each value followed by a newline character):</p><pre>hawk.1.header<br>1529992949<br>261EDD5E9A7C<br>GET<br>/smrt/api/cdn_token/<br>connectv3.smrt.wwprojects.com<br>443<br>q/t+NNAkQZNlq/aAD6PlexImwQTxwgT2MahfTa9XRLA=</pre><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/84a9bb77d21ae3f0ee99941546513437/href">https://medium.com/media/84a9bb77d21ae3f0ee99941546513437/href</a></iframe><p><strong>Generate the MAC (Message Authentication Code)</strong></p><p>The request MAC is calculated using HMAC with the specified hash algorithm sha256 and the key over the normalized request string. The result is base64-encoded to produce the request MAC:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8fbc639885e016cc74be6e2efe0141da/href">https://medium.com/media/8fbc639885e016cc74be6e2efe0141da/href</a></iframe><pre>UJu120qHBk8LOdJP2BXOIQr9jy8MrCOSpHxV3cEqmag=</pre><p><strong>Getting Together</strong></p><p>We will compose HTTP GET request with the generated MAC.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5017f335838751edf0439882ae4723f7/href">https://medium.com/media/5017f335838751edf0439882ae4723f7/href</a></iframe><p>This is a sample HTTP GET request generated from the above code:</p><pre>{ url: &#39;<a href="https://connectv3.smrt.wwprojects.com/smrt/api/train_arrival_time_by_id/?station=Commonwealth&#39;">https://connectv3.smrt.wwprojects.com/smrt/api/train_arrival_time_by_id/?station=Commonwealth</a>&#39;,<br> method: &#39;GET&#39;,<br> headers:<br> { Connection: &#39;Keep-Alive&#39;,<br> &#39;User-Agent&#39;: &#39;SMRT Connect/3.0 Android/7.0&#39;,<br> &#39;Accept-Encoding&#39;: &#39;gzip&#39;,<br> &#39;Content-Type&#39;: &#39;text/plain&#39;,<br> Referer: &#39;<a href="https://connectv3.smrt.wwprojects.com/smrt/&#39;">https://connectv3.smrt.wwprojects.com/smrt/</a>&#39;,<br> Authorization: &#39;Hawk id=”ww-connectv3-android”,mac=”UJu120qHBk8LOdJP2BXOIQr9jy8MrCOSpHxV3cEqmag=”,hash=”q/t+NNAkQZNlq/aAD6PlexImwQTxwgT2MahfTa9XRLA=”,ts=”1529993914&quot;,nonce=”ADBC4BFE5F0B”’ } }</pre><p>If there is no error, we will get he response feedback in JSON format:</p><pre>{ results:<br> [ { status: 1,<br> platform_ID: &#39;COM_A&#39;,<br> code: &#39;EW20&#39;,<br> next_train_arr: &#39;1&#39;,<br> mrt: &#39;Commonwealth&#39;,<br> subseq_train_arr: &#39;6&#39;,<br> next_train_destination: &#39;Pasir Ris&#39;,<br> subseq_train_destination: &#39;Pasir Ris&#39; },<br> { status: 1,<br> platform_ID: &#39;COM_B&#39;,<br> code: &#39;EW20&#39;,<br> next_train_arr: &#39;Arr&#39;,<br> mrt: &#39;Commonwealth&#39;,<br> subseq_train_arr: &#39;5&#39;,<br> next_train_destination: &#39;Tuas Link&#39;,<br> subseq_train_destination: &#39;Joo Koon&#39; } ] }</pre><p>It is very simple and clean !!. With this you can run the Node app on Raspberry Pi and display the arrival times on mini LCD display 😆</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/0*b0D3R7q5Jp3tYMyF" /></figure><h3>Deploy to Google Cloud</h3><p>Clone the app on my <a href="https://github.com/ferrygun/TrainOnDemand">Git repo</a> and download it to a folder. We will be using Google Cloud service to host and run the app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/206/1*ppOJMX4LJJf3NFVpPxrF5g.png" /></figure><p>Run the following command to deploy to Google Cloud:</p><pre><strong>gcloud app deploy</strong></pre><p>Once it success, take note the URL <a href="https://trainondemand-192214.appspot.com/"><strong><em>https://XXXXXXXX.appspot.com</em></strong></a><em>. </em>We will use this information to setup the webhook in <strong>Dialogflow</strong> shortly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HZWCFRvM2MROyPBUxXUf3Q.png" /></figure><h3>More Fun with Dialogflow</h3><p>Create an free account on <strong>Dialogflow (</strong><a href="https://dialogflow.com/">https://dialogflow.com/</a>) and create a new agent. I have created mine: <strong>TrainOnDemand</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/983/1*JIyTPtvtsGdSyhtDyrFXaw.png" /></figure><h4><strong>Intents</strong></h4><p>We will create and modify the following intents:<br><strong>About</strong>, <strong>Default Exit Intent</strong>, <strong>Default Fallback Intent</strong>, <strong>Default Welcome Intent</strong>, <strong>Refresh </strong>and <strong>SayMRTStation</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/982/1*HVNQFm9pynnNY0ktCQdexw.png" /></figure><h4><strong>About Intent</strong></h4><p>If user asking “<em>who are you?</em>”, the bot will reply “<em>I am Train On Demand, I can let you know the train arrival timing status. Just let me know the station name for East West Line, North South Line and Circle Line of SMRT stations.</em>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/920/1*DDbjv-mBdoo4ksgpZUhMnA.png" /></figure><h4>Default Exit Intent</h4><p>If user says “<em>good bye</em>”, “<em>bye</em>” or “<em>no</em>”, the bot will reply “<em>Good bye and have a safe journey!</em>” or “<em>Be well and have a pleasant journey!</em>” and will end the conversation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/911/1*ORG_gIljE6slKgNMWdlVIw.png" /></figure><h4>Default Fallback Intent</h4><p>If the bot can’t recognize the response from user, for example user is saying unknown MRT station, the bot will reply “<em>I could not find that MRT station. What is the correct MRT station name ?</em>”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/914/1*Jo2F8837JdpRk-8nVcqAaQ.png" /></figure><h4>Default Welcome Intent</h4><p>When user starts the conversation with bot, it will reply “<em>Hi! I am Train On Demand. I can provide you the train arrival status. Which MRT station that you would like to know ?</em>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/919/1*fp9A9FXl0V70da9ym24A7g.png" /></figure><h4>Refresh</h4><p>User says “<em>Refresh</em>” to update the train arrival information. <br>If there is no response from the backend, the bot will reply “<em>Searching took a little longer than expected, please say it again now.</em>”. This is to avoid the Dialogflow ends the conversation due to timeout (no response from the backend).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/916/1*31j64GLaQvN-IbH70HcD8g.png" /></figure><h4><strong>SayMRTStation</strong></h4><p>To check the train arrival time information on the specific MRT station name.</p><p>Under <strong>Action and parameters</strong>, there is a link to the <strong>entity: @MRTStation</strong>. We will cover it shortly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/921/1*nE-S5VurqeH6dHV3IopBCw.png" /></figure><h4>Entities</h4><p>We will create one entity <strong>MRTStation </strong>that comprises of the list of available MRT stations in Singapore. Just ignore the <strong>Platform </strong>entity in the screenshot.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uDaKCPNTu0UWDT_IaOOB0A.png" /></figure><h4><strong>MRTStation Entity</strong></h4><p>You can add and update the MRT station list in this section. Also include the station code, like EW21 for Buona Vista station.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*plr33645eTMb9-kgn7lkBA.png" /></figure><p>We are done with Intents and Entities.</p><h4><strong>Test &amp; Deploy</strong></h4><p>Select <strong>Fulfillment</strong> and enter the URL in this format and set it to enable.</p><pre><a href="https://trainondemand-192214.appspot.com/hook"><strong>https://xxxxxxxxxx.appspot.com/hook</strong></a></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1019/1*WUqJEOmEFc1-esf2b-A1vA.png" /></figure><p>Select <strong>Integrations </strong>and click <strong>Integration Settings</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/999/1*x2sdFzPM5fQ8bu8vGDEgNA.png" /></figure><p>Click <strong>Test</strong> to test the app and make sure everything is work as expected.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/728/1*Y3_WHQFICLi6EKTxXudjIQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r8BTPw3ccQuFnl7bo7EUtg.png" /></figure><p>Once you have tested, now you can click <strong>Manage Assistant App</strong> to deploy to production.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qQqZJMDkstDVY6MlG-9o6w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l-VW_nL3IuCj9ydVwVAx0A.png" /></figure><p>That’s it! Now you can create a new app for Google Assistant. Let me know if you have any questions and until next time!! 👌</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2F3e59ef%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2F3e59ef&amp;image=http%3A%2F%2Fapi.screenshotlayer.com%2Fapi%2Fcapture%3Faccess_key%3Dfe59908dad3baab69ffab249a2224b03%26viewport%3D1024x612%26width%3D1000%26url%3Dhttps%253A%252F%252Fupscri.be%252F3e59ef%253Fscreenshot&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/7078d8ad19192c4c53d3bf199468e4ab/href">https://medium.com/media/7078d8ad19192c4c53d3bf199468e4ab/href</a></iframe><figure><a href="https://chatbotslife.com/bot-communities-mastermind-group-d2dae9876709#.53x0py6ou"><img alt="" src="https://cdn-images-1.medium.com/max/255/1*6XUspT9JOSq0w0Fi35HIaA.png" /></a></figure><figure><a href="https://m.me/ChatbotsLife"><img alt="" src="https://cdn-images-1.medium.com/max/255/1*c1LDMH5vbnIz9rmAka8Hwg.png" /></a></figure><figure><a href="https://chatbotslife.com/how-to-get-a-free-chatbot-b1fb9dfe109#.z9dtp2sy0"><img alt="" src="https://cdn-images-1.medium.com/max/255/1*D0Jf3dI6ZThtqcfwDYY7mg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=71cf02103e8" width="1" height="1" alt=""><hr><p><a href="https://blog.chatbotslife.com/make-google-assistant-app-to-check-train-arrival-times-with-dialogflow-71cf02103e8">Make Google Assistant App to Check Train Arrival Times with Dialogflow</a> was originally published in <a href="https://blog.chatbotslife.com/">Chatbots Life</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build Wearable Smart Glass App For Warehouse Picking Solution]]></title>
            <link>https://medium.com/@ferrygunawan/build-wearable-smart-glass-app-for-warehouse-picking-solution-a981faeb0980?source=rss-e0c3772a9b36------2</link>
            <guid isPermaLink="false">https://medium.com/p/a981faeb0980</guid>
            <category><![CDATA[smart-glass]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[augmented-reality]]></category>
            <category><![CDATA[sap]]></category>
            <category><![CDATA[vuzix]]></category>
            <dc:creator><![CDATA[Ferry Djaja]]></dc:creator>
            <pubDate>Wed, 20 Jun 2018 07:09:55 GMT</pubDate>
            <atom:updated>2018-06-20T09:01:42.262Z</atom:updated>
            <content:encoded><![CDATA[<p>Smart glass in warehouse picking operation is the efficient way to increase the productivity and streamline the picking process.</p><p>The benefit of using the smart glass for warehouse picking operations:</p><ul><li>Hands Free display is everything you need to boost the accuracy and productivity.</li><li>Augmented reality to capture the working environment and provide the relevant information.</li><li>Cheap and flexible compare with the high-end handheld/RF scanner.</li><li>Simple Output Process without impacting (low impact) on the current business process. A business process that does not require an intensive interaction between the user and the application are ideal candidates for a Smart Glass solution.</li><li>No dedicated infrastructure. We just can tap to the existing infrastructure as long as there is WiFi connectivity.</li><li>Easily integrated with ERP (SAP) and WMS (Oracle) back-end.</li></ul><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F9Wv9k_ssLcI%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D9Wv9k_ssLcI&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F9Wv9k_ssLcI%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/6d988c5fb271aa7900fc47afc3a529c6/href">https://medium.com/media/6d988c5fb271aa7900fc47afc3a529c6/href</a></iframe><p>I would like to walk through how to build a wearable glass android app based on the Vuforia template and we will be using M300 Vuzix SDK and some opensource libraries. I don’t have Vuzix M300 yet, but we will be using Android phone for demo purpose.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ihO5EjM9TBnJwgtKbpBdEw.png" /></figure><p>Let’s get started!!</p><h4><strong>Download Vuforia SDK and Sample App</strong></h4><p>Create a Vuforia account and go to <a href="https://developer.vuforia.com/downloads/sdk"><strong>https://developer.vuforia.com/downloads/sdk</strong></a><strong> </strong>to download the required SDK. On this post, we will be creating an Android app. Let’s download the SDK for Android.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/816/1*fF3RWDh4KVQRUe5vTBhtdg.png" /></figure><p>Extract the SDK on your local folder. For my case is:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/833/1*WQS-5z26KNltIzn8y4J_bQ.png" /></figure><p>Download the sample app, we will be using <strong>Video Playback </strong>as a base. Go to <strong>Download &gt; Samples &gt;</strong> <strong>Advanced Topics</strong> section and download it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*K_z2Y_BYndm0zW26nuu8wQ.png" /></figure><p>Once you have downloaded, extract the <strong>VideoPlayback-7–1–34.zip</strong> to your sample folder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/864/1*ix7uSNf9GEA7JYZH6gSxkg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/838/1*c7wu3vXYl6nCoEe9aT7p2A.png" /></figure><p>We also need to create a license. Go to <a href="https://developer.vuforia.com/targetmanager/licenseManager/summaryForFreePlan"><strong>https://developer.vuforia.com/targetmanager/licenseManager/summaryForFreePlan</strong></a> to create a license.</p><p>Enter the app name: <strong>Quickware </strong>and click Confirm.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/840/1*LoG7Z9PU-0GciVDxzxM42Q.png" /></figure><p>Note down the license key.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/798/1*UIxuaSy_YNWzm9jJrDJzFw.png" /></figure><h4><strong>Import to Android Studio</strong></h4><p>Open your Android Studio and select <strong>Open an existing Android Studio project</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/801/1*7kLPZvGJ2LkawZJyRd-FTA.png" /></figure><p>Now go to <strong>app &gt; res &gt; values &gt; strings.xml</strong> and update the <strong>app_name</strong> and <strong>app_description</strong>. Let’s name it <strong>Quickware</strong>.</p><pre>&lt;<strong>string name=&quot;app_name&quot;</strong>&gt;Quickware&lt;/<strong>string</strong>&gt;<br>&lt;<strong>string name=&quot;app_description&quot;</strong>&gt;Quickware Wearable Glass&lt;/<strong>string</strong>&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4eIq1Li76NHJ0_xtCZ6q_A.png" /></figure><p>We will remove the Splash and About Screen activity. Open <strong>AndroidManifest.xml</strong> file and replace with the below content.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n6qMXYXM7etnKPqS-av0Ow.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8ee5a1bff935f04bb1a91785eb493b08/href">https://medium.com/media/8ee5a1bff935f04bb1a91785eb493b08/href</a></iframe><p>We will add Vuforia license key. Open <strong>app &gt; src &gt; main &gt; java &gt; com &gt; vuforia &gt; samples &gt; SampleApplication &gt; SampleApplicationSession</strong>.</p><p>Under <strong>setInitParameters</strong>, add your Vuforia license key.</p><pre>Vuforia.<em>setInitParameters</em>(<strong>mActivity</strong>, <strong>mVuforiaFlags</strong>, <strong>&quot;YOUR_VUFORIA_LICENSE_KEY&quot;</strong>);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cxdGE1sa36dujm_B8bF71g.png" /></figure><p>Add this point you can run the demo app and you will see the app running without splash and about screen.</p><h4><strong>Install the Vuzix M300 SDK</strong></h4><p>Create an account for Vuzix at <a href="https://www.vuzix.com/Developer/Dashboard"><strong>https://www.vuzix.com/Developer/Dashboard</strong></a><strong>.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/786/0*YKUkgd5NMSs7TEeo.png" /><figcaption>Vuzix M300 Smart Glass</figcaption></figure><p>Follow the instruction to install the M300 SDK in Android Studio:</p><p><a href="https://www.vuzix.com/Developer/KnowledgeBase/Detail/43">Vuzix | View The Future</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9fIpjAJhDbBYnzfjVP6iKw.png" /></figure><p>Now we need to update the project to use M300 SDK. Follow the below guideline:</p><p><a href="https://www.vuzix.com/Developer/KnowledgeBase/Detail/53">Vuzix | View The Future</a></p><p>Even though now we are not using the Vuzix speech recognition SDK (as I don’t have the device yet), we will still add the library and use in the future.</p><h4>Download Other Libraries</h4><p>We also need to download the required libraries:</p><ol><li><strong>ZXing 1D/2D barcode image processing library</strong> (<a href="https://github.com/zxing/zxing">https://github.com/zxing/zxing</a>)<br>Download <strong>core-3.3.3.jar</strong> from <a href="https://repo1.maven.org/maven2/com/google/zxing/core/3.3.3/">https://repo1.maven.org/maven2/com/google/zxing/core/3.3.3/</a></li><li><strong>Google gson</strong>(<a href="https://github.com/google/gson">https://github.com/google/gson</a>)<br>Download <strong>gson-2.8.1.jar </strong>from <a href="https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.1/">https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.1/</a></li><li><strong>Ksoap2-android</strong> (<a href="http://simpligility.github.io/ksoap2-android/index.html">http://simpligility.github.io/ksoap2-android/index.html</a>)<br>Download <strong>ksoap2-android-assembly-3.6.2-jar-with-dependencies.jar</strong> from <a href="https://oss.sonatype.org/content/repositories/ksoap2-android-releases/com/google/code/ksoap2-android/ksoap2-android-assembly/3.6.2/ksoap2-android-assembly-3.6.2-jar-with-dependencies.jar">https://oss.sonatype.org/content/repositories/ksoap2-android-releases/com/google/code/ksoap2-android/ksoap2-android-assembly/3.6.2/ksoap2-android-assembly-3.6.2-jar-with-dependencies.jar</a></li></ol><p>Copy all jar files to <strong>libs</strong> folder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/903/1*AqTUqsXFpLrf0lgb-8oa9g.png" /></figure><p>Open the <strong>build.gradle</strong> on the <strong>module app</strong> and replace the content with the following.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lSF4VGxt3brH1-fFX9b6NQ.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0b8992f766a0e067e4a9417f13d5a8ed/href">https://medium.com/media/0b8992f766a0e067e4a9417f13d5a8ed/href</a></iframe><p>You can verify the setting under <strong>Project Structure &gt; Modules &gt; app</strong> as well.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/820/1*h7WX-ZEWdHtZ3bvJiCQ3rg.png" /></figure><h4>Create the App</h4><p>Let’s start coding now !!</p><p>Open <strong>VideoPlayback.java</strong> and modify it.</p><p>On the <strong>OnCreate</strong> method, we add the <strong>addOverlayView</strong> to execute the workflow and create the transparent HTML menu.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MjZxqEz7ghf-XEp5cEYEmw.png" /></figure><p>Calling the workflow is initiated at:</p><pre><strong>commandInvocation </strong>= <strong>new </strong>CommandInvocation(getApplicationContext(), <strong>webView</strong>, <strong>this</strong>);</pre><p>Let’s take look at <strong>CommandInvocation.java</strong>. The workflow is defined in the <strong>WorkFlow.json</strong>. We will take a look at this file shortly.</p><p>Also we define the method to execute the task based on the workflow, for example method <strong>displayInputShipmentId()</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kyXNSVUJhsFG8PEczOf1AA.png" /></figure><h4><strong>Workflow</strong></h4><p>Workflow is the process flow in the program to validate and execute the objects or methods defined in the process flow based on the input command. Workflow is defined in <strong>WorkFlow.json</strong> under Asset folder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KYDTO4xUrqBXCTLiX6b73w.png" /></figure><p>The workflow consist of list of available <strong>Commands</strong> and <strong>Tasks</strong>.</p><p>We only can execute the commands that are listed there, for example: <strong>scan</strong>, <strong>next</strong>, <strong>done</strong>, <strong>auto</strong>, etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/296/1*hcc5s-_STHLTgZN0G8scfA.png" /></figure><p>The entry point of the workflow is the task id <strong>start </strong>which will execute the <strong>targetRef</strong>: <strong>inputShipmentId</strong>. We will talk about this <strong>targetRef</strong>, <strong>commandRef</strong> shortly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/332/1*87zyjIyzlEOWo_HvpTpcew.png" /></figure><p>Under <strong>Task Id: forward</strong>, we define the following fields:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*k1AwKuu1YArLkBc4oseQDQ.png" /></figure><ul><li><strong>name</strong> (mandatory field)</li><li><strong>commandRef </strong>(optional field)<strong><br></strong>To refer and execute the objects defined in <strong>functionRef</strong>, <strong>validfatorRef</strong> or<strong> targetRef </strong>.</li><li><strong>functionRef </strong>(optional field)<br>To refer and execute the method defined in this field, for example: method <strong>scanShipmentId</strong>. We need to create the corresponding method in <strong>CommandInvocation.java</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/859/1*EwwjsTfczlA7PDXM16CauQ.png" /></figure><ul><li><strong>validatorRef </strong>(optional field)<br>To validate the input before the <strong>targetRef</strong> is executed, for example <strong>isInputCorrect</strong>. This method will always return true or false. We need to create the corresponding method in <strong>CommandInvocation.java</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/959/1*nn10de2FNkJSpa74QnrfJA.png" /></figure><ul><li><strong>targetRef </strong>(optional field) <br>To refer and execute the objects defined in <strong>targetRef</strong>. We need to create the corresponding method in <strong>CommandInvocation.java</strong>. The method should be in this format: <strong>“display” + targetRef</strong> with the first letter is a capital letter. For example: <strong>displayInputShipmentId</strong>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/511/1*upUKeUIQMQIqD_5lEF7NRQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/958/1*mEwdBj34P8DZj1m25T8tEg.png" /></figure><p>The core workflow methods can be found in <strong>WorkFlow.java</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G8zVyNWf6VXFE-YSRXXrNg.png" /></figure><h4><strong>Calling the Workflow</strong></h4><p>On the initial menu, the app will execute the workflow to display the menu to enter the Shipment Number.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/958/1*mEwdBj34P8DZj1m25T8tEg.png" /></figure><p>The above method is calling the JavaScript function <strong>LoadInputScreen</strong> defined in the <strong>app.js</strong>. which will generate the HTML5 menu.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jS3h7cYxFQlI-vOKmruj_w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ihO5EjM9TBnJwgtKbpBdEw.png" /></figure><p>There are three commands in this HTML5 menu: <strong>Scan</strong> to launch the scanner, <strong>Next</strong> to proceed to the next screen once the scan is done. <strong>Cancel</strong> to clear the input value and <strong>Reset</strong> to refresh the box.</p><p>Let’s take a look at <strong>Scan</strong> command.</p><p>When the user click the Scan link, the JavaScript <strong>runScanFunction()</strong> in <strong>app.js</strong> will be executed and it will call the <strong>receiveCommandStringFromJS</strong> method in <strong>WebViewJavaScriptInterface.java </strong>with the input command <strong>“scan”</strong>. And then it will call the <strong>updateView</strong> method in <strong>CommandInvocation.java </strong>which will then trigger the workflow.</p><pre><strong>//in app.js<br>function </strong>runScanFunction() {<br>  <strong>var </strong>command = <strong>&quot;scan&quot;</strong>;<br>  myJSscriptToNativeCodeHandler.receiveCommandStringFromJS(command);<br>}</pre><pre><strong>//in WebViewJavaScriptInterface.java</strong><br>@JavascriptInterface<br><strong>public void </strong>receiveCommandStringFromJS(String commandKeyWord) {<br>    <strong>final </strong>String generatedSelectCommand = commandKeyWord;<br>    <strong>new </strong>Handler(<strong>this</strong>.<strong>context</strong>.getMainLooper()).post(<strong>new </strong>Runnable() {<br>        <strong>public void </strong>run() {<br>            WebViewJavaScriptInterface.<em>commandInvocation</em>.updateView(generatedSelectCommand);<br>        }<br>    });<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/820/1*N-LM1oDL0vtPBDhp8DpMcQ.png" /></figure><p>And the workflow is executed in method <strong>triggerNextStep</strong> in <strong>Workflow.java.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U0V9R6pGmI69yTd0fCPOig.png" /></figure><p>If you notice, under this method there is <strong>validateScreen</strong> method that will execute against the <strong>validatorRef </strong>value: <strong>isInputCorrect</strong>.</p><p><strong>isInputCorrect</strong> method is defined in <strong>CommandInvocation.java</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-YXOUEEcO6EXKG9Gwoy4Pw.png" /></figure><p>The same flow is apply for all other commands: <strong>Next</strong>, <strong>Cancel</strong> and <strong>Reset</strong>.</p><p>All the source codes can be found on my Git repo.</p><p><strong>Future Works</strong></p><p>I list down the open items for the future works:</p><ul><li>To implement Vuzix Speech Recognition.</li><li>To connect with ERP SAP backend using OData services.</li><li>To enhance the workflow process.</li></ul><p>That’s all that we need and I hope it gives you a good glance to start developing the wearable smart glass app.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a981faeb0980" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>