GirlieMac! BlogArbitrary Web and Mobile Writing by Tomomi ImuraJekyll2021-09-22T16:49:54-07:00https://girliemac.com/Tomomi Imurahttps://girliemac.com/https://girliemac.com/blog/2021/07/12/microsoft-beginners-sketchnotes2021-07-12T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p>A year ago, <a href="https://twitter.com/girlie_mac/status/1280180665367982080">I joined Microsoft</a> and it has been an interesting ride so far, despite the fact that I joined during the pademic. (Leaving the previous workplace, Slack without going to office was interesting in a different way though…)</p>
<p>Although my main focus is supporting Microsoft 365 developer products, I have gotten chances to work on numerous projects outside of the immediate team, including open technologies, education, localization, etc. to keep myself involved in something I have been always working on for my entire tech career, and not tied to the Microsoft proprietary technologies.</p>
<h2 id="doodling-for-scientists">Doodling for scientists</h2>
<p>One of my re-discovered passion is doodling, especially something technical, which I had neglected for a long time in my tech career.</p>
<p>My past life was a researcher at am environmental microbiology research lab a long time ago, and my lab had a lot of my doodles on the wall. These were the lab protocols and the doodles included a lot of Erlenmeyer flasks, tubes, Petri dishes, and stuff.</p>
<p>I remember people kept telling me how the visual reference helped them.</p>
<h2 id="doodles-to-help-educating-developers">Doodles to help educating developers</h2>
<p>And now I think this can be totally applied for this different type of science— computer science and programming, and my new teammates in Microsoft agree.</p>
<p>In fact, Microsoft advocacy team fully enbraces the way to support developers with visual helps and already have amazing sketchnote and technical illustration artists who are actually software engineers and program managers, including <a href="https://twitter.com/sketchthedocs">Nitya Narasimhan</a>, <a href="https://twitter.com/jenlooper">Jen Looper</a>, <a href="https://twitter.com/dasani_decoded">Dasani Madipalli</a>, and <a href="https://twitter.com/manekinekko">Wassim Chegham</a>.</p>
<p>Recently, we have released a few open-source beginner-focused curriculums on GitHub, including <a href="https://github.com/microsoft/Web-Dev-For-Beginners">Web Dev for Beginners</a> and <a href="https://github.com/microsoft/ML-For-Beginners">ML for Beginners</a>, and I worked on sketchnote-style summaries for some lessons.</p>
<p>Here are some of my setchnotes—</p>
<p><em>Web Dev 101 - Intro programming</em>
<img src="/assets/images/articles/2021/07/webdev101-programming.png" alt="WebDev - Intro Programming" /></p>
<p><em>Machine Learning - Regressions</em>
<img src="/assets/images/articles/2021/07/ml-regression.png" alt="Machine Learning - Regressions" /></p>
<p>The curriculums are under MIT license and the content including my sketchnotes are under Creative Commons. The printable versions are <a href="https://github.com/girliemac/a-picture-is-worth-a-1000-words">available as TIFF format</a> too.</p>
<h2 id="tech-doodlers--sketchnote-artists-to-follow">Tech Doodlers & Sketchnote artists to follow</h2>
<p>If you are also a visual learners who want to follow people who doodle on Twitter, here’s my list!</p>
<ul>
<li><a href="https://twitter.com/nitya">Nitya Narasimhan</a> - Cloud, Azure, live sketchnotes, Microsoft tech</li>
<li><a href="https://twitter.com/jenlooper">Jen Looper</a> - Web, Vue.js, Microsoft tech</li>
<li><a href="https://twitter.com/dasani_decoded">Dasani Madipalli</a> - ML, Microsoft tech</li>
<li><a href="https://twitter.com/manekinekko">Wassim Chegham</a> - Web, protocols, Microsoft tech</li>
<li><a href="https://twitter.com/rachelnabors">Rachel Nabors</a> - Web, React, comics</li>
<li><a href="https://twitter.com/chiuki">Chiu-Ki Chan</a> - Android, live sketchnotes</li>
<li><a href="https://twitter.com/corey_latislaw">Corey Leigh Latislaw</a> - Android, live sketchnotes</li>
<li><a href="https://twitter.com/lariki">Lara Martín</a> - Android, live sketchnotes</li>
<li><a href="https://twitter.com/VPoltrack">Virginia Poltrack</a> - Android, Star Wars</li>
<li><a href="https://twitter.com/Mappletons">Maggie Appleton</a> - Web, UX</li>
<li><a href="https://twitter.com/sailorhg">Amy, a.k.a. sailor mercury</a> - programming, <a href="https://shop.bubblesort.io/">Bubble sort zines</a></li>
<li><a href="https://twitter.com/b0rk">Julia Evans</a> - Unix, programming</li>
</ul>
<p>I am pretty sure I missed a lot of people here, so please let me know if you know more wonderful techinical artists.</p>
https://girliemac.com/blog/2021/02/20/web-monetization-bitcoin2021-02-20T00:00:00-08:00Tomomi Imurahttps://girliemac.com<p>As I am writing this on Feb 20, 2021, Bitcoin (<a href="https://www.fool.com/quote/crypto/bitcoin/btc/">CRYPTO:BTC</a>) has hit a $1 trillion market cap. Investors who thought it was a joke have started jumped into the cryptocurrencies frenzy.</p>
<p>Although the ideas of decentralized market and blockchain are fascinating, I didn’t think the value of BTC would increase much, so I have spent them on things like yoga pants and flights to Europe. I try not to think about how much worth it in today’s rate. There are just too many what-if scenarios in my life. (BTW, the economy-class ticket I got was about 1.3 BTC. I let you figure it out.)</p>
<p>Now friends are asking me about advice on cryptocurrency and <a href="https://www.coinbase.com/join/girlie_mac">Coinbase referrals</a>, however, because I can be the worst financial advisor to ruin your life, I am not going to tell you how to invest, or even how to mine in this article, instead, I am going to tell you about <strong>Web Monetization</strong> and how to receive micropayments in $BTC and other currencies including various cryptocurrencies, like $DOGE if you want, through your website.</p>
<p>I may sound like I am selling you snake oil, but I just thought this may be a good opportunity to talk about the web standard topic.</p>
<p><img src="/assets/images/articles/2021/02/doge-web-monetization-1000x420.jpg" alt="doge meme" /></p>
<h2 id="web-monetization--interledger">Web Monetization & Interledger</h2>
<p>According to the draft submitted to W3C, <a href="https://webmonetization.org/specification.html">Web Monetization</a> is an API that allows websites to request small payments from users facilitated by the browser and the user’s Web Monetization provider.</p>
<p>In a nutshell, Web Monetization is an open web API, consists of HTML, JavaScript API, and uses the <a href="https://interledger.org/">Interledger protocol</a>, an open protocol for moving money and enabling payments.</p>
<h2 id="implementing-web-monetization">Implementing Web Monetization</h2>
<p>Although implementation for browsers is straight-forward, it requires some prerequisits as currently, you need (1) a Web Monetization service provider and (2) an Interledger Protocol-enabled wallet to monetize on web.</p>
<p>The services I personally use to implement Web Monetization are:</p>
<ol>
<li><a href="https://coil.com">Coil</a> - Web Monetization service provider</li>
<li><a href="https://uphold.com/signup?referral=5f261fb476">Uphold</a> - ILP-enabled wallet</li>
</ol>
<p>How <strong>Coil</strong> works is that is checks if the website is web monetized, and if it does, stream the payment to the site. A small amount is paid by Coil members, who pay a flat fee to access exclusive content and ad-free experiences. Coil provides browser extensions for browsers including Chrome, Edge, and Firefox, while <a href="https://www.pumabrowser.com/"><strong>Puma browser</strong></a> is natively powered on Coil and supports Web Monetization API out of the box.</p>
<p>And <strong>Uphold</strong> is a digital wallet that allows you to receive payments with an Interledger payment pointer. This is where you can receive the payment also sell, buy, and trade.</p>
<h3 id="setting-up-your-wallet">Setting up Your Wallet</h3>
<p>Coil supports multiple wallets, but I am using Uphold to generate your Interledger payment pointer here.</p>
<p>First, open an <a href="https://uphold.com/signup?referral=5f261fb476">Uphold</a> account.</p>
<p>Once you signed up and all, you are going to generate an ILP address (Interledger payment pointer).</p>
<p>Go to <strong>Transact</strong>, then from the <strong>Anything to Anything</strong> (Right pane), select <strong>From</strong> dropdown menu:</p>
<p><img src="/assets/images/articles/2021/02/uphold-transact-01.png" alt="Screenshot - Uphold 1" /></p>
<p>Select <strong>Interledger</strong>:</p>
<p><img src="/assets/images/articles/2021/02/uphold-transact-02.png" alt="Screenshot - Uphold 2" /></p>
<p>Then pick a currency of your choice— USD, BTC, ETH, XRP, DOGE… there are 27 fiat currencies and
34 Cryptocurrencies to choose from:</p>
<p><img src="/assets/images/articles/2021/02/uphold-transact-03.png" alt="Screenshot - Uphold 3" /></p>
<p>Copy the address that looks like <code class="language-plaintext highlighter-rouge">$ilp.uphold.com/SoMethIngLiKEthis0</code>:</p>
<p><img src="/assets/images/articles/2021/02/uphold-transact-04.png" alt="Screenshot - Uphold 4" /></p>
<p>You will need the address in Coil (the next step) and in your HTML code later.</p>
<h3 id="setting-up-coil">Setting up Coil</h3>
<p>There are two membership types— <a href="https://coil.com/signup">Coil membership</a> to support web-monetized content and <a href="https://coil.com/creator">creator membership</a> for you to monetize. I am walking you through the latter—</p>
<p>First, sign up for a <a href="https://coil.com/creator"><strong>Coil creator account</strong></a> and click <strong>Start monetizing. It’s free</strong> button.</p>
<p>Once you created your account (and verified your email etc.), you will need to set up your payout wallet.</p>
<p>Go to <a href="https://coil.com/settings/payouts"><strong>Payout</strong></a>, click <strong>Setup</strong> under <strong>Uphold</strong> (unless you chose Gatehub as your wallet):</p>
<p><img src="/assets/images/articles/2021/02/coil-payouts-01.png" alt="Screenshot - Coil 1" /></p>
<p>and enter the ILP address that you generated at Uphold and save:</p>
<p><img src="/assets/images/articles/2021/02/coil-payouts-02.png" alt="Screenshot - Coil 2" /></p>
<p>Next, you are going to include a meta tag with the information on your website to finalize.</p>
<h2 id="monetizing-your-web">Monetizing Your Web</h2>
<p>If you already have some website or web apps, you are ready to monetize. All you need is to include the <code class="language-plaintext highlighter-rouge"><meta></code> in your head of HTML:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><title></span>Welcome to My Homepage<span class="nt"></title></span>
<span class="nt"><meta</span>
<span class="na">name=</span><span class="s">"monetization"</span>
<span class="na">content=</span><span class="s">"$ilp.uphold.com/6NxbkHNq9N84"</span><span class="nt">></span>
<span class="nt"></head></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p>Make sure to use your own ILP address as the meta content, unless you want me to receive all of your payment. Then, deploy your web and you are ready to monetize 💰</p>
<h3 id="monetizing-your-content-on-devto">Monetizing Your Content on Dev.to</h3>
<p>Even if you don’t have your own websites, some content platforms do support Web Monetization. Take a look at the <a href="https://help.coil.com/docs/monetize/content/platforms">list of providers</a>.</p>
<p>For example, if you write some technical content on Dev.to like I do, you can include your ILP address to monetize your content there too.</p>
<p>Sign in and go to the <a href="https://dev.to/settings/misc"><strong>Settings</strong></a> > <strong>Extensions</strong> > <strong>Web monetization</strong>, and enter your ILP address there and save.</p>
<p><img src="/assets/images/articles/2021/02/devto-monetize.png" alt="devto" /></p>
<p>That’s it.
Now all you need is to wait to get paid in BTC (or whatever you picked) and HODL ;-)</p>
<p>I hope you enjoyed the article. Web platform to the moon 🚀🌕</p>
https://girliemac.com/blog/2020/06/18/javascript-spread-operator2020-06-18T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p><em>This articles is created based on my own <a href="https://twitter.com/girlie_mac/status/1263955788990566400">tweet</a> posted on May 22, 2020</em></p>
<p><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fca3o3sF--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/i/4mqpk334i9k78gaw6q7n.png" alt="ES6 tricks" /></p>
<p>ES6 (ECMAScript 2015, the 6th edition) was finalized 5 years ago, and brought us a significant amount of new syntax and features to help you write complex code better and simpler.</p>
<p>I am assuming that many of you have consumed more calories from the syntactic sugar by adopting new features like class declarations, <code class="language-plaintext highlighter-rouge">let</code> / <code class="language-plaintext highlighter-rouge">const</code>, and arrow function expression, and so on, but how about some of the lesser-known <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">Spread operator</a>?</p>
<p>Here, I would like to share some good usages of spread operator, a.k.a three-dots that I’ve found while I was coding (and StackOverflowing, I don’t lie about how I code!).</p>
<h2 id="what-do-three-dots-do">What do Three Dots do?</h2>
<p>First, there are two “three-dots” sugars introduced in ES6. One is <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters"><strong>Rest parameter</strong></a>, which allows us to use an arbitrary number of arguments, and another is <strong>Spread operator</strong>, which also has the similar syntax with three dots, but it is more like the reversed version- it takes the array itself, not arguments.</p>
<p>In this article, I am showing tricks that uses spread syntax. Looking at the practical examples may be far easier to understand what it does than by reading the definitions!</p>
<hr />
<h2 id="concat">Concat</h2>
<p>You say “cat” so I say meow.</p>
<p>Let’s concatenate two arrays. Here we have two arrays that represent cat fur coat colors:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">arr1</span> <span class="o">=</span> <span class="p">[</span><span class="dl">'</span><span class="s1">solid</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">bicolor</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">tabby</span><span class="dl">'</span><span class="p">];</span>
<span class="kd">const</span> <span class="nx">arr2</span> <span class="o">=</span> <span class="p">[</span><span class="dl">'</span><span class="s1">calico</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">tortoiseshell</span><span class="dl">'</span><span class="p">];</span>
</code></pre></div></div>
<p>This is how we traditionally did before ES6 using <code class="language-plaintext highlighter-rouge">concat()</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">conCats</span> <span class="o">=</span> <span class="nx">arr1</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">arr2</span><span class="p">);</span>
<span class="c1">// ['solid', 'bicolor', 'tabby', 'calico', 'tortoiseshell']</span>
</code></pre></div></div>
<p>Now you can simply write with the ES6 spread syntax like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">conCats</span> <span class="o">=</span> <span class="p">[...</span><span class="nx">arr1</span><span class="p">,</span> <span class="p">...</span><span class="nx">arr2</span><span class="p">];</span>
<span class="c1">// ['solid', 'bicolor', 'tabby', 'calico', 'tortoiseshell']</span>
</code></pre></div></div>
<h2 id="convert-a-string-to-array">Convert a string to array</h2>
<p>Have you been asked to reverse a string, or check if a string is a palindrome at job interviews? The questions you got may be more complex, but these are pretty common interview questions for software engineers.</p>
<p>Anyway, the first step to solve the question is likely to convert the given string to an array.</p>
<p>You have a given string:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">str</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">kitty</span><span class="dl">'</span><span class="p">;</span>
</code></pre></div></div>
<p>With pre-ES6 JavaScript, use <code class="language-plaintext highlighter-rouge">split()</code> to get each letter in an array:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">newArr</span> <span class="o">=</span> <span class="nx">str</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">''</span><span class="p">);</span> <span class="c1">// ['k', 'i', 't', 't', 'y'];</span>
</code></pre></div></div>
<p>Now with the ES6 spread syntax, you can achieve the same as:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">newArr</span> <span class="o">=</span> <span class="p">[...</span><span class="nx">str</span><span class="p">];</span> <span class="c1">// ['k', 'i', 't', 't', 'y'];</span>
</code></pre></div></div>
<h2 id="find-max-or-min">Find Max or Min</h2>
<p>Let’s say, you have a given set of numbers,</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">10</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">12</span>
</code></pre></div></div>
<p>To find the largest (or smallest) number from the set of numbers, you can use <code class="language-plaintext highlighter-rouge">Math.max()</code> (or <code class="language-plaintext highlighter-rouge">Math.min()</code>) and pass the given numbers as input parameters like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">max</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">12</span><span class="p">);</span>
</code></pre></div></div>
<p>Now with the ES6 spread syntax, you can pass an array of numbers:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">nums</span> <span class="o">=</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">12</span><span class="p">];</span>
<span class="kd">const</span> <span class="nx">max</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(...</span><span class="nx">nums</span><span class="p">);</span> <span class="c1">// 12</span>
</code></pre></div></div>
<h2 id="copy-an-array">Copy an Array</h2>
<p>You can also create a shallow copy of an array with the spread syntax.</p>
<p>You have an array,</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">allCatNames</span> <span class="o">=</span> <span class="p">[</span><span class="dl">'</span><span class="s1">chewie</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">leia</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">yoda</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">chewie</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">luke</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">leia</span><span class="dl">'</span><span class="p">];</span>
</code></pre></div></div>
<p>And onne way to get a shallow copy of the array with the pre-ES6 is using <code class="language-plaintext highlighter-rouge">slice()</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">allCatNamesCopy</span> <span class="o">=</span> <span class="nx">allCatNames</span><span class="p">.</span><span class="nx">slice</span><span class="p">();</span>
</code></pre></div></div>
<p>Now with ES6 spread syntax, you can simply do:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">allCatNamesCopy</span> <span class="o">=</span> <span class="p">[...</span><span class="nx">allCatNames</span><span class="p">];</span>
</code></pre></div></div>
<h2 id="remove-dups-from-an-array">Remove Dups from an Array</h2>
<p>The array, <code class="language-plaintext highlighter-rouge">allCatNames</code> above has some duplicated values (<code class="language-plaintext highlighter-rouge">chewie</code> and <code class="language-plaintext highlighter-rouge">leia</code> appeared twice in the list). If want to remove the duplicates, you’ll write multiple lines of code with pre-ES6 JavaScript-</p>
<p>You probably would iterate the array. And at each loop, map each value in an object to track if the key in the object is unique, and if yes, the value is pushed to a new array. Then at the end of the loop, you have the new array only with unique values.</p>
<p>You can actually achieve this in one line of code with spread syntax by creating a new array with combination of the spread syntax with the <code class="language-plaintext highlighter-rouge">Set</code> object:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">catNames</span> <span class="o">=</span> <span class="p">[...</span><span class="k">new</span> <span class="nb">Set</span><span class="p">(</span><span class="nx">allCatNames</span><span class="p">)];</span>
<span class="c1">// ['chewie', 'leia', 'yoda', 'luke'];</span>
</code></pre></div></div>
<p>Ta-da, this saves a lot of code!</p>
<h2 id="collecting-html-elements-in-an-array">Collecting HTML Elements in an Array</h2>
<p>If you are a front-end JavaScript developer, this trick may be useful when you manipulate DOM-</p>
<p>Let’s say, when you re trying to grab every element with the class name, <code class="language-plaintext highlighter-rouge">.cat</code>, you probably use <code class="language-plaintext highlighter-rouge">querySelectorAll()</code> to get the collection of the DOM nodes.</p>
<p>But <code class="language-plaintext highlighter-rouge">document.querySelectorAll('.cat')</code> returns a static <em>NodeList</em>, which is an array-like, but not exactly an array that you can iterate over it.</p>
<p>So in some occasions, you need to convert a NodeList to Array. Traditionally, you probably have been writing code like this, which doesn’t seem so intuitive:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">catElementArray</span> <span class="o">=</span> <span class="p">[].</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">.cat</span><span class="dl">'</span><span class="p">));</span>
</code></pre></div></div>
<p>Now with the spread syntax, you can rewrite as followings:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">catElementArray</span> <span class="o">=</span> <span class="p">[...</span><span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">.cat</span><span class="dl">'</span><span class="p">)];</span>
</code></pre></div></div>
<p>This looks more intuitive, doesn’t it?</p>
<hr />
<p>Well, if you like the three-dots notation or not, now you see that the spread operator can be quite handy when you work with arrays and objects.</p>
<p>I would be happy if I just convinced you to use the three-dots in your daily code from now on. Surely, there are more clever ways to write code with using the spread operator, so if you know the tricks, please share with me and the rest of the JS community!</p>
<h3 id="wants-to-find-out-more-about-esnext">Wants to find out more about ES.Next?</h3>
<p>I will be giving a talk, <em>ECMeowScript - What’s new in JavaScript Explained with Cats</em> at <a href="https://forwardjs.com/">Forward JS</a> (<del>San Francisco</del> virtual) in July and <a href="https://webdirections.org/">Web Directions</a> (<del>Sydney</del> virtual) in September, so I hope you can catch my talk! 🐱</p>
<p>Ciao!</p>
https://girliemac.com/blog/2019/04/02/javascript-i18n-reiwa-era2019-04-02T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p>As Emperor Akihito of Japan is set to abdicate soon, the Japanese government announced on April 1st that the reign of the next emperor will be known as the Reiwa (令和) era.</p>
<p><img src="https://cdn.cnn.com/cnnnext/dam/assets/190401111401-yoshihide-suga-reiwa-announcement-exlarge-169.jpg" alt="reiwa" /></p>
<p>You may wonder like, “Wait, Japan hasn’t adopted the Gregorian calendar system!?” – Well, yes Japan did over 100 years ago, however, Japan use both “Western” calendar and the unique Japanese Imperial year, which is based on the legendary foundation of Japan by Emperor Jimmu in 660 BC.</p>
<p>Anyway, what I want to talk about in my blog is not about Japanese history but JavaScript <code class="language-plaintext highlighter-rouge">Intl.DateTimeFormat</code> object that enable language and locale specific date and time formatting.</p>
<p><a href="https://tc39.github.io/ecma402/">The ECMAScript Internationalization API</a> was originally introduced in 2010, and currently in the 6th Edition, to help localize the output of dates, numbers, and currencies in Javascript. And this has been well supported by major browsers now. (See <a href="https://caniuse.com/#search=Intl">Can I use</a>)</p>
<p>One of the property of the <code class="language-plaintext highlighter-rouge">Intl</code> object is <a href="https://tc39.github.io/ecma402/#datetimeformat-objects"><code class="language-plaintext highlighter-rouge">DateTimeFormat</code></a>, which enable language and locale specific date and time formatting.</p>
<p>So yes, with the <code class="language-plaintext highlighter-rouge">Intl.DateTimeFormat</code> object, you can automatically print out the Japan local date and time with Japanese imperial era!</p>
<h2 id="using-datetimeformat">Using DateTimeFormat</h2>
<p>Without specifying a locale / language, <code class="language-plaintext highlighter-rouge">DateTimeFormat</code> uses the default locale and the default time zone, so when I am on my machine in the US:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nx">Intl</span><span class="p">.</span><span class="nx">DateTimeFormat</span><span class="p">().</span><span class="nx">format</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">())</span>
</code></pre></div></div>
<p>returns today’s date in en-US as:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"4/2/2019"
</code></pre></div></div>
<h3 id="specifying-locales">Specifying Locales</h3>
<p>You can get a localized date and time by using a locale identifier (language code and a country/region code) as the <code class="language-plaintext highlighter-rouge">locales</code> argument, for example:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nx">Intl</span><span class="p">.</span><span class="nx">DateTimeFormat</span><span class="p">(</span><span class="dl">'</span><span class="s1">ru-RU</span><span class="dl">'</span><span class="p">).</span><span class="nx">format</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">())</span>
<span class="c1">// "02.04.2019"</span>
</code></pre></div></div>
<p>and Japan is:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nx">Intl</span><span class="p">.</span><span class="nx">DateTimeFormat</span><span class="p">(</span><span class="dl">'</span><span class="s1">ja-JP</span><span class="dl">'</span><span class="p">).</span><span class="nx">format</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">())</span>
<span class="c1">// "2019/4/2"</span>
</code></pre></div></div>
<p>Okay, but you still see the Gregorian calendar year here. So how can you make it fully localized with Imperial year?</p>
<p>Well, the locale identifier, <code class="language-plaintext highlighter-rouge">ja-JP</code>, is not enough and you need to add an extention <code class="language-plaintext highlighter-rouge">-u-ca-japanese</code>. I don’t know exactly what it means but all I can say is <code class="language-plaintext highlighter-rouge">ja-JP-u-ca-japanese</code> is an awkwardly complicated local code.</p>
<blockquote>
<p>Edited: Thank you, <a href="https://twitter.com/brandelune">ジャンクリストフ</a> for letting me know that <code class="language-plaintext highlighter-rouge">-u</code> in the identifier indicates an extension, <code class="language-plaintext highlighter-rouge">-ca</code> says defines a type of calendar, in this case, <code class="language-plaintext highlighter-rouge">-japanese</code> calendar.
For more info on locale data, see: <a href="http://www.unicode.org/reports/tr35/#Locale_Extension_Key_and_Type_Data">Unicode Technical Standard #35</a></p>
</blockquote>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nx">Intl</span><span class="p">.</span><span class="nx">DateTimeFormat</span><span class="p">(</span><span class="dl">'</span><span class="s1">ja-JP-u-ca-japanese</span><span class="dl">'</span><span class="p">).</span><span class="nx">format</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">())</span>
<span class="c1">// "31/4/2"</span>
</code></pre></div></div>
<p>Now, we know it is the year 31. But what year is it? How can we know the Imperial name!?</p>
<p>To get the whole deal, use the <code class="language-plaintext highlighter-rouge">options</code> argument, in this case use <code class="language-plaintext highlighter-rouge">era</code>:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nx">Intl</span><span class="p">.</span><span class="nx">DateTimeFormat</span><span class="p">(</span><span class="dl">'</span><span class="s1">ja-JP-u-ca-japanese</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span><span class="na">era</span><span class="p">:</span><span class="dl">'</span><span class="s1">long</span><span class="dl">'</span><span class="p">}).</span><span class="nx">format</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">())</span>
<span class="c1">// ta-da! "平成31年4月2日"</span>
</code></pre></div></div>
<p>Oooh yeah, now you get “平成31年4月2日”!</p>
<p>Let’s try one more thing with Thai locale:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nx">Intl</span><span class="p">.</span><span class="nx">DateTimeFormat</span><span class="p">(</span><span class="dl">'</span><span class="s1">th-TH-u-nu-thai</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span><span class="na">era</span><span class="p">:</span><span class="dl">'</span><span class="s1">long</span><span class="dl">'</span><span class="p">}).</span><span class="nx">format</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">())</span>
<span class="c1">// "๒ ๔ พุทธศักราช ๒๕๖๒"</span>
</code></pre></div></div>
<p>Woooh, I have no idea how to read this, but it is the year 2562 in Buddhist calendar!</p>
<p>Well, you can find details on the options and learn more about this topic on <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat">MDN Web Docs</a></p>
<p>Also, I quickly wrote up this silly little web app called <strong>Is it Reiwa (令和) yet?</strong> on <a href="https://reiwa-yet.glitch.me/">https://reiwa-yet.glitch.me/</a>. This should say <strong>No</strong> until May 1, 2019, when Crown Prince Naruhito becomes a new emperor, the imperial year should be changed to 令和元年, <em>if the new era is implemented in your browser!!!</em> So let’s update your browser and see!</p>
<hr />
<p>By the way, I totally didn’t blog on my own website last year, as writing technical tutorials has become a part of my day job, I don’t write when I am not paid as often. I hope I can start writing random technical posts again.</p>
https://girliemac.com/blog/2017/12/28/edward-tufte-data2017-12-28T00:00:00-08:00Tomomi Imurahttps://girliemac.com<p>Earlier this month, I finally attended Edward Tufte’s one-day course on <strong>Presenting Data and Information</strong>, where I learned fundamental design strategies for information displays including sentences, tables, diagrams, maps, charts, images, video, and data visualizations.</p>
<p>My actual live-notes were several more pages, but I summarized them nicer after the class:</p>
<h2 id="notes-from-the-class">Notes from the Class</h2>
<ul>
<li>Data paragraph</li>
<li>Evidence and conclusion</li>
<li>6 fundamental principle of analytical design</li>
<li>Presenting Data</li>
</ul>
<p><img src="/assets/images/articles/2017/12/tufte-data-note-01.jpg" alt="my notes from Tufte course 1" /></p>
<ul>
<li>Data annotations</li>
<li>Data display on maps & topography</li>
<li>Words, numbers, and images</li>
<li>Meaning and space</li>
</ul>
<p><img src="/assets/images/articles/2017/12/tufte-data-note-02.jpg" alt="my notes from Tufte course 2" /></p>
<h3 id="books-by-tufte">Books by Tufte</h3>
<p>If you are interested taking his class too, check out <a href="https://www.edwardtufte.com/tufte/courses">the course overview</a>! The course also includes four books:</p>
<ul>
<li><a href="https://www.amazon.com/gp/product/1930824165/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&tag=gm063-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1930824165&linkId=a0aca55af5083f3c5e4c1f5e72e37700">Beautiful Evidence</a></li>
<li><a href="https://www.amazon.com/gp/product/0961392142/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&tag=gm063-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=0961392142&linkId=74b35f7af67dc8422da8c2f10ec2ae5e">The Visual Display of Quantitative Information</a></li>
<li><a href="https://www.amazon.com/gp/product/0961392118/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&tag=gm063-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=0961392118&linkId=a6d33bce12d815dd5098baac95fbaa85">Envisioning Information </a></li>
<li><a href="https://www.amazon.com/gp/product/0961392126/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&tag=gm063-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=0961392126&linkId=e83e21e5695ae751143bc9dbef82c36e">Visual Explanations</a>: Images and Quantities, Evidence and Narrative</li>
</ul>
https://girliemac.com/blog/2017/12/27/state-of-web-platform2017-12-27T00:00:00-08:00Tomomi Imurahttps://girliemac.com<p>In October, I attended the annual Chrome Dev Summit, which I never missed since the first one.</p>
<p>I was mostly just listening the talks at the conference, but did make this note form the keynote, “The state of Chrome and the Web Platform” by my former-boss at Palm webOS DevRel, <a href="https://twitter.com/dalmaer">Dion Almaer</a> and <a href="https://twitter.com/bgalbs">Ben Galbraith</a>!</p>
<h2 id="notes-from-the-talk">Notes from the Talk</h2>
<p><img src="/assets/images/articles/2017/12/state-of-web.jpg" alt="my notes from The State of Web" /></p>
https://girliemac.com/blog/2017/12/26/git-purr2017-12-26T00:00:00-08:00Tomomi Imurahttps://girliemac.com<p>Although I am a “STEM all the way” person (I studied microbiology and worked as a software engineer), I consider myself more a creative side and I am a visual learner – When I learn new things, I tend to doodle rather than writing everything down. Even when I was studying math and logics, I drew everything to understand the concepts.</p>
<p>Time has passed by and I stopped taking notes with doodles as much as I used to be, until one day I met amazing ladies like <a href="https://twitter.com/chiuki">Chiuki</a> and <a href="https://twitter.com/corey_latislaw">Corey</a> who were sketchnoting at tech conferences, and here I am, so inspired and started doodling again.</p>
<p>After several attempts and tweets at Google I/O, I started wanting to make <em>my own notes</em> into something more visually appealing and presentable so that I can share my notes with everybody else who want to learn the same subjects.</p>
<p>Now I created the git doodles. With cats.
I <a href="https://twitter.com/girlie_mac/status/905270297128865792">tweeted</a>, and my notifications exploded.</p>
<p>Here’s the series of my doodles. Enjoy!</p>
<h2 id="git-purr-git-pull">git purr (git pull)</h2>
<p><img src="/assets/images/articles/2017/12/git-purr.jpg" alt="git purr (git pull)" /></p>
<h2 id="git-meowge-git-merge--git-rebase">git meowge (git merge & git rebase)</h2>
<p><img src="/assets/images/articles/2017/12/git-meowge.jpg" alt="git meowge (git merge & git rebase)" /></p>
<h2 id="git-puss-git-push">git puss (git push)</h2>
<p><img src="/assets/images/articles/2017/12/git-puss.jpg" alt="git puss (git push)" /></p>
<h2 id="git-cherry-pick--git-log">git cherry-pick & git log</h2>
<p>Now I “handwrite” the doodle digitally with Procreate on iPad!
<img src="/assets/images/articles/2017/12/git-cherry-pick.jpg" alt="git cherry-pick" /></p>
https://girliemac.com/blog/2017/02/12/filterous2-release2017-02-12T00:00:00-08:00Tomomi Imurahttps://girliemac.com<p><img src="/assets/images/articles/2017/02/filterous-2.png" alt="filterous-2" /></p>
<p>I recently released <strong>Filterous 2</strong>, an open-source Instagram-like image manipulation library for Javascript and node.js on <a href="https://www.npmjs.com/package/filterous">npm</a>.</p>
<p>This is a revamped version of Filterous, which was written for JavaScript for browser about 4 years ago, and this version works on both Node.js and browser, and comes with pre-defined Instagram-like filters (with the same filter names and very similar effects).</p>
<p>To see how it works, check out the <a href="https://girliemac.github.io/filterous-2/demo-browser">browser demo</a>!</p>
<p>This demo does not reply on the server, and created solely with front-end JavaScript (and it is vanilla) and browser version of Filterous 2.</p>
<h2 id="story-behind-the-project">Story Behind the Project</h2>
<p>Between 2012 and 2014, I was a member of W3C’s Core Mobile Community Group. To demonstrate the HTML5 APIs for mobile phones, I have written the demo called <a href="https://github.com/coremob/camera">Coremob Camera</a>, and show this at the W3C booth at Mobile World Congress in Barcelona (<a href="https://www.w3.org/blog/2013/04/interview-demonstrating-web-ap/">Interview</a>) in 2013, and talked about the technologies behind at W3C Conference in San Francisco (<a href="https://www.youtube.com/watch?v=3Afi-v-m_Gc">My talk on YouTube</a>).</p>
<p>Basically the app was like a web app version of Instagram (which, we withheld from using the name for the legal reason.)- you take a picture from the mobile phone camera, and apply a filter to give the glamorous finish. To add a “filter” feature, I wrote some code to manipulate the original jpeg image, and later, I separated the code out of the whole app to open-sourced it as an independent library.</p>
<p>Four years has passed, and now I decided to make it for node.js, then used <a href="http://browserify.org/">Browerify</a> to export it for browser use.</p>
<h2 id="how-it-manipluate-images">How It Manipluate Images</h2>
<p>Filterous takes an image into a <code class="language-plaintext highlighter-rouge">canvas</code> to manipulate the pixels of the image. Unlike the CSS filters that alters how the image appearance only on browsers, the JavaScript library actually alters the pixel color values. So you can actually download the modified image.</p>
<p>The <code class="language-plaintext highlighter-rouge">CanvasRenderingContext.getImageData()</code> method of the Canvas API returns an <code class="language-plaintext highlighter-rouge">ImageData</code> object representing the underlying pixel data of the canvas, and the <code class="language-plaintext highlighter-rouge">data</code> property of <code class="language-plaintext highlighter-rouge">pixelData</code> stores the color info of an each pixel in the canvas. (The diagram below shows a canvas size of only 9x9 pixel to make it simple).</p>
<p>Each pixel in the data array consists of 4 bytes values- red, green, blue, and alpha channel, and each of the R (red), G (green), B (blue) and A (alpha transparency) values can take values between 0 and 255.</p>
<p><img src="https://github.com/girliemac/filterous-2/blob/master/images/canvas-pixels.png?raw=true" alt="canvas image manipulation" /></p>
<p>I referenced numerous sources (credited them in my source code) for the algorithms to alter a color image to grayscale, brighten, saturate, etc. and I used the combinations to give the Instagram-like predefined filters. I probably spent most of my time mimicking the entire set of the filter they offer!</p>
<p>The source code and documentation are available on <a href="https://github.com/girliemac/filterous-2">GitHub</a>. If you’d like to file bugs or contribute, please feel free to send me issue and pull requests!</p>
https://girliemac.com/blog/2017/01/06/facebook-apiai-bot-nodejs2017-01-06T00:00:00-08:00Tomomi Imurahttps://girliemac.com<p><img src="/assets/images/articles/2017/01/cover-facebook-apiai-bot.png" alt="Facebook Messenger Bot with api.ai" /></p>
<p>Hey, happy new year!!!</p>
<p>Previously, I created a <a href="http://www.girliemac.com/slack-httpstatuscats/">HTTP Status Cats bot for Slack</a> (and its tutorial on <a href="https://medium.com/@girlie_mac/creating-a-slack-command-bot-from-scratch-with-node-js-distribute-it-25cf81f51040#.12dzr1mx1">Medium</a>), and this time I tried with <strong>Facebook Messenger</strong> with some interesting 3rd party APIs, and I decide to give <strong>API.ai</strong> a try.</p>
<p>As you may have heard of, API.ai, which recently acquired by Google, provides a conversational platform for natural language processing and it allows us to create bots easily.</p>
<p>Writing apps with the services aren’t hard, however it requires some time reading the docs to figure out how to set them up, so I would like to share my experiences as this tutorial so hopefully you can write your bot in less time.</p>
<p><img src="https://raw.githubusercontent.com/girliemac/fb-apiai-bot-demo/master/public/images/fb-bot.gif" alt="messenger bot" /></p>
<p>There are two major parts:</p>
<ol>
<li>Setting up a Facebook Messenger App and writing the webhook</li>
<li>Using API.ai Small Talk domain and creating a custom Intents</li>
</ol>
<p>My step-by-step instruction uses Node.js, so if you’d like to follow the how-to, make sure <a href="https://nodejs.org">Node.js</a> is installed on your machine.</p>
<p><a href="https://github.com/girliemac/fb-apiai-bot-demo/tree/tutorial-01"><strong>The source code</strong></a> (on <em>tutorial-01</em> branch) is on GitHub.</p>
<p>*(Updated on Jan 9: The bot has been approved by Facebook so you can try the bot!) *
<strong>Live Demo</strong> - Scan the code below (the one looks sort of like a QR code) from the Messenger App on mobile, or access on m.me/tomomiBot from browser.</p>
<p><img src="https://raw.githubusercontent.com/girliemac/fb-apiai-bot-demo/master/public/images/messenger-scan-code.png" alt="Facebook scan code" /></p>
<h2 id="1-developing-a-facebook-messenger-app">1. Developing a Facebook Messenger App</h2>
<p>Before configuring your Messenger app on Facebook Developer, let’s create a bare minimum webhook with Node.js to get started.</p>
<h3 id="setting-up-a-temporary-webhook-endpoint-with-ngrok">Setting Up a Temporary Webhook Endpoint with ngrok</h3>
<p>I choose <strong>ngrok</strong> to serves a localhost to a public URL because it is simple and easy to use. This URL will be used as a Messenger webhook endpoint during the development, so you don’t need to deploy to a server until the app is completed.</p>
<p>Download <a href="https://ngrok.com/">ngrok</a>, install it on your machine, and run with a port number, let’s use 5000:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ngrok http 5000
</code></pre></div></div>
<p>When you start ngrok, it will display a public URL of your tunnel in the terminal. We will need the URL later when setting up the Facebook app. (In the screenshot, the URL is <code class="language-plaintext highlighter-rouge">https://47ba4dd4.ngrok.io</code>)</p>
<p><img src="/assets/images/articles/2017/01/ngrok.png" alt="ngrok" /></p>
<h3 id="writing-a-webhook-with-expressjs">Writing a Webhook with Express.js</h3>
<p>Create your app directory and set up your Node.js app:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm init
</code></pre></div></div>
<p>Once you configure your app, install <strong>Express</strong> and <strong>body-parser</strong>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ npm install express body-parser --save
</code></pre></div></div>
<p>Let’s create a <code class="language-plaintext highlighter-rouge">webhook.js</code>, and instantiate express and listen the server to port 5000, or whatever the port you have set with ngrok:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">bodyParser</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">body-parser</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">bodyParser</span><span class="p">.</span><span class="nx">json</span><span class="p">());</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">bodyParser</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="na">extended</span><span class="p">:</span> <span class="kc">true</span> <span class="p">}));</span>
<span class="kd">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PORT</span> <span class="o">||</span> <span class="mi">5000</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Express server listening on port %d in %s mode</span><span class="dl">'</span><span class="p">,</span> <span class="nx">server</span><span class="p">.</span><span class="nx">address</span><span class="p">().</span><span class="nx">port</span><span class="p">,</span> <span class="nx">app</span><span class="p">.</span><span class="nx">settings</span><span class="p">.</span><span class="nx">env</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Now, create HTTP GET and POST route method to handle the command:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* For Facebook Validation */</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/webhook</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="dl">'</span><span class="s1">hub.mode</span><span class="dl">'</span><span class="p">]</span> <span class="o">&&</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="dl">'</span><span class="s1">hub.verify_token</span><span class="dl">'</span><span class="p">]</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">tuxedo_cat</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">200</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="dl">'</span><span class="s1">hub.challenge</span><span class="dl">'</span><span class="p">]);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">403</span><span class="p">).</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="cm">/* Handling all messenges */</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/webhook</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">object</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">page</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">entry</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">entry</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">entry</span><span class="p">.</span><span class="nx">messaging</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">event</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">message</span> <span class="o">&&</span> <span class="nx">event</span><span class="p">.</span><span class="nx">message</span><span class="p">.</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">sendMessage</span><span class="p">(</span><span class="nx">event</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">200</span><span class="p">).</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre></div></div>
<p>This is how you receive messages to your webhook via Facebook Messenger- All requests should come via <code class="language-plaintext highlighter-rouge">post</code>, while the <code class="language-plaintext highlighter-rouge">GET</code> route is only used at the time you configure your Facebook app.</p>
<p>Where you see the <code class="language-plaintext highlighter-rouge">tuxedo_cat</code>, just use an arbitrary string. You will need later when setting up your Facebook app.</p>
<p>Run the code, and go to the next step.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>node webhooks.js
</code></pre></div></div>
<h3 id="setting-up-a-facebook-app">Setting Up a Facebook App</h3>
<p>You need a <strong>Facebook Page</strong> to set up your chat bot. Create one from <a href="https://www.facebook.com/pages/create">facebook.com/pages/create</a>. Choose a category, and select a sub category from the dropdown and fill out the required filed. Then click <strong>Get Started</strong>.</p>
<p><img src="/assets/images/articles/2017/01/create-a-page.png" alt="FB Page" /></p>
<p>Then create an app at <a href="https://developers.facebook.com/quickstarts/?platform=web">developers.facebook.com/quickstarts</a>.</p>
<p>Give it a name and click the button, then fill out the required info:</p>
<p><img src="/assets/images/articles/2017/01/create-an-app.png" alt="Create a FB App" /></p>
<p>Once your app is created, follow the steps to configure or skip it to your Dashboard.</p>
<p><img src="/assets/images/articles/2017/01/FB-dashboard.png" alt="Create a FB App" /></p>
<p>Click <strong>Add Product</strong> from the left menu, then choose <strong>Messenger</strong>. Click Get Started.</p>
<p><img src="/assets/images/articles/2017/01/create-an-app-add-product.png" alt="Create a FB App" /></p>
<p>At the <strong>Token Generation</strong>, (1) choose the page you just created from the dropdown menu, and it will generate a token (2) that you will need to include in your node code.</p>
<p>Then, at the <strong>Webhooks</strong>, (3) click the <strong>Setup Webhooks</strong> button:</p>
<p><img src="/assets/images/articles/2017/01/create-an-app-messenger.png" alt="Create a FB App" /></p>
<p>In the dialog, fill out the (1) <strong>Callback URL</strong> with your ngrok URL, (2) the random string for validation (the one you’ve specified in your ‘GET’ route in the <code class="language-plaintext highlighter-rouge">webhook.js</code>), then (3) check <strong>messages</strong>.</p>
<p><img src="/assets/images/articles/2017/01/create-an-app-messenger-webhook.png" alt="Create a FB App" /></p>
<p>Click the <strong>Verify and Save</strong>. If you get a red icon with <strong>x</strong> at the Callback URL, it means the URL is not validated- either the URL is wrong or your node code is not properly running. Otherwise, you are ready to get back to code.</p>
<h3 id="writing-a-super-simple-chat-bot">Writing a Super Simple Chat Bot</h3>
<p>Install <strong>request</strong> to <code class="language-plaintext highlighter-rouge">POST</code> messages:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>request <span class="nt">--save</span>
</code></pre></div></div>
<p>Continue with your <code class="language-plaintext highlighter-rouge">webhook.js</code>, let’s implement <code class="language-plaintext highlighter-rouge">sendMessage()</code> that simply replies the sender an echo to just test your Messenger bot:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">request</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">function</span> <span class="nx">sendMessage</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">sender</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">sender</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">message</span><span class="p">.</span><span class="nx">text</span><span class="p">;</span>
<span class="nx">request</span><span class="p">({</span>
<span class="na">url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://graph.facebook.com/v2.6/me/messages</span><span class="dl">'</span><span class="p">,</span>
<span class="na">qs</span><span class="p">:</span> <span class="p">{</span><span class="na">access_token</span><span class="p">:</span> <span class="nx">PAGE_ACCESS_TOKEN</span><span class="p">},</span>
<span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span><span class="p">,</span>
<span class="na">json</span><span class="p">:</span> <span class="p">{</span>
<span class="na">recipient</span><span class="p">:</span> <span class="p">{</span><span class="na">id</span><span class="p">:</span> <span class="nx">sender</span><span class="p">},</span>
<span class="na">message</span><span class="p">:</span> <span class="p">{</span><span class="na">text</span><span class="p">:</span> <span class="nx">text</span><span class="p">}</span>
<span class="p">}</span>
<span class="p">},</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Error sending message: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Error: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">response</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Where you see the <code class="language-plaintext highlighter-rouge">PAGE_ACCESS_TOKEN</code>, use the generated token.</p>
<p>Try running the code. This acts as a very simple bot, which interact the Messenger platform to receive a message and echo the message as the reply- Go to [https://m.me/YOUR-PAGE] and start a conversation. If your the simple bot works correctly, it just replies the exactly what you send:</p>
<p><img src="/assets/images/articles/2017/01/facebook-basic.gif" alt="Simple echo bot" /></p>
<p>Your entry is simply echoed back. This is boring, so let’s use API.ai next to make this conversation more interesting.</p>
<h2 id="2-using-apiai-with-your-facebook-messenger-bot">2. Using API.ai with Your Facebook Messenger Bot</h2>
<p><a href="https://api.ai">API.ai</a> allows developers to integrate your app with the AI system with speech-to-text and natural language processing.</p>
<p>Let’s get started with API.ai by <a href="https://console.api.ai">sigining up</a>.</p>
<p>Once you get your account, create an agent. You can either click the button that says <strong>CREATE AGENT</strong> or from the menu.</p>
<p><img src="/assets/images/articles/2017/01/apiai-create-agent.png" alt="Create a FB App" /></p>
<p>Give it a name and fill out the required info:</p>
<p><img src="/assets/images/articles/2017/01/apiai-agent-setup.png" alt="Create a FB App" /></p>
<p>Make sure to click the <strong>Save</strong> button on the top every time you make changes.</p>
<h3 id="making-small-talk-with-your-messenger-bot">Making “Small Talk” with your Messenger Bot</h3>
<p>Instead of having your bot just echo you, let’s give it the API.ai’s Small Talk feature. This gives your bot an ability to have simple conversations.</p>
<p>From the left menu (if the menu is not visible, click the “Hamburger menu icon” at the top left to open), click <strong>Domains</strong>, then activate the <strong>Small Talk</strong>.</p>
<p><img src="/assets/images/articles/2017/01/apiai-small-talk.png" alt="Create a FB App" /></p>
<p>Once activated, click <strong>View details</strong> then turn on the <em>Fulfillment</em> so that you can later use this feature in your app and customize.</p>
<p><img src="/assets/images/articles/2017/01/apiai-small-talk-desc.png" alt="Create a FB App" /></p>
<p>Try the <strong>Console</strong> at the right hand side. You can either speak or type to test the Small Talk domain:</p>
<p><img src="/assets/images/articles/2017/01/apiai-console.png" alt="Create a FB App" /></p>
<p>Now let’s use this feature in your bot. You can always come back here to customize the conversations.</p>
<h4 id="using-apiai-with-nodejs">Using API.ai with Node.js</h4>
<p>It is actually possible to integrate API.ai with FB Messenger without programming, however, to make it fully customize in the way you want to interact with your FB app, let’s use the service programmatically.</p>
<p>First, install <a href="https://www.npmjs.com/package/apiai">API.ai node.js library</a>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>apiai
</code></pre></div></div>
<p>You need your API.ai API key and API secret to use the service with your bot. From the menu, click the “Config” icon to get your API key (“Client access token”):</p>
<p><img src="/assets/images/articles/2017/01/apiai-apikey.png" alt="Create a FB App" /></p>
<p>And go back to your <code class="language-plaintext highlighter-rouge">webhook.js</code> and initialize <code class="language-plaintext highlighter-rouge">apiai</code> with the API key:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span><span class="err"> </span><span class="nx">apiaiApp</span><span class="err"> </span><span class="o">=</span><span class="err"> </span><span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">apiai</span><span class="dl">'</span><span class="p">)(</span><span class="nx">CLIENT_ACCESS_TOKEN</span><span class="p">);</span>
</code></pre></div></div>
<p>Refer the usage on its <a href="https://www.npmjs.com/package/apiai">npm doc</a>. It is pretty simple- you just pass a text to API.ai, and do something when you get the response (the <code class="language-plaintext highlighter-rouge">response</code> event).</p>
<p>Now, let’s modify the <code class="language-plaintext highlighter-rouge">sendMessage()</code> :</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">sendMessage</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">sender</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">sender</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">message</span><span class="p">.</span><span class="nx">text</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">apiai</span> <span class="o">=</span> <span class="nx">apiaiApp</span><span class="p">.</span><span class="nx">textRequest</span><span class="p">(</span><span class="nx">text</span><span class="p">,</span> <span class="p">{</span>
<span class="na">sessionId</span><span class="p">:</span> <span class="dl">'</span><span class="s1">tabby_cat</span><span class="dl">'</span> <span class="c1">// use any arbitrary id</span>
<span class="p">});</span>
<span class="nx">apiai</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">response</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Got a response from api.ai. Let's POST to Facebook Messenger</span>
<span class="p">});</span>
<span class="nx">apiai</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">error</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">apiai</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>What the code sample above doing is basically getting the info (passed as a param) sent from a user via Messenger, and pass the text content to API.ai. Once the API.ai returns the answer, the <code class="language-plaintext highlighter-rouge">response</code> event is triggered.</p>
<p>Where you see the <code class="language-plaintext highlighter-rouge">// Got a response…</code> comment in the code sample above, let’s <code class="language-plaintext highlighter-rouge">POST</code> the response to the Messenger API:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">...</span>
<span class="nx">apiai</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">response</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">aiText</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">result</span><span class="p">.</span><span class="nx">fulfillment</span><span class="p">.</span><span class="nx">speech</span><span class="p">;</span>
<span class="nx">request</span><span class="p">({</span>
<span class="na">url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://graph.facebook.com/v2.6/me/messages</span><span class="dl">'</span><span class="p">,</span>
<span class="na">qs</span><span class="p">:</span> <span class="p">{</span><span class="na">access_token</span><span class="p">:</span> <span class="nx">PAGE_ACCESS_TOKEN</span><span class="p">},</span>
<span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span><span class="p">,</span>
<span class="na">json</span><span class="p">:</span> <span class="p">{</span>
<span class="na">recipient</span><span class="p">:</span> <span class="p">{</span><span class="na">id</span><span class="p">:</span> <span class="nx">sender</span><span class="p">},</span>
<span class="na">message</span><span class="p">:</span> <span class="p">{</span><span class="na">text</span><span class="p">:</span> <span class="nx">aiText</span><span class="p">}</span>
<span class="p">}</span>
<span class="p">},</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">response</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Error sending message: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Error: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">response</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Now, let’s test your bot. Run the node code, and try sending some messages. If everything is working, you should get replies from the bot:</p>
<p><img src="/assets/images/articles/2017/01/facebook-apiai-smalltalk.gif" alt="Tada! Bot with api.ai" /></p>
<p>Awesome.</p>
<h3 id="making-the-bot-tell-you-weather-condition">Making the Bot Tell You Weather Condition</h3>
<p>When you activate the Small Talk from the <strong>Domains</strong>, you may have noticed there are more presets like Weather and Flight Schedules, etc. To use these services, it looks like you need to send inquiry to their sales peeps.</p>
<p><img src="/assets/images/articles/2017/01/apiai-domains.png" alt="api.ai domains" /></p>
<p>However, of course as an engineer, you can always call the 3rd party APIs to add the features by yourself instead of just flipping the switch and pay. So let’s make your bot to tell users the current weather forecast with the <a href="http://openweathermap.org/current">Open Weather Map API</a>.</p>
<p>The goal here is that when a user ask something like “How is the weather in San Francisco?”, your bot will reply with the current weather condition in the given city.</p>
<h4 id="creating-weather-intents">Creating Weather Intents</h4>
<p>First, to customize the conversational user interfaces, you need to understand <a href="https://docs.api.ai/docs/key-concepts">the key concepts</a> of API.ai, especially <strong>Entities</strong> and <strong>Intents</strong> for now.</p>
<p><strong>Intents</strong> represent a mapping between what a user says and what action should be taken by your software. To make your bot reply the user with a weather info, you need to create a specific Intents.</p>
<p>From the menu, go to <strong>Intents</strong> and click the CRETAE INTENT button:</p>
<p><img src="/assets/images/articles/2017/01/apiai-intents-00.png" alt="api.ai intents" /></p>
<p>Give it a name, such as <em>weather.city</em>.</p>
<p>Then create some contexts. Enter a phrase like, “How is the weather in San Francisco?”</p>
<p><img src="/assets/images/articles/2017/01/apiai-intents-01.png" alt="api.ai intents" /></p>
<p>Select the city name (“San Francisco”), and you will get a popup. What you see here are pre-defined <strong>entities</strong>. There are many entities in the list but what you need here is a collection of cities. So choose <code class="language-plaintext highlighter-rouge">@sys.geo-city</code>. The city name will be highlighted.</p>
<p>Major city names have been provided already so you do not need to create them, however if you need to define special entities that not listed there, such as types of cars, food, etc, you will need to create manually. (I am not covering how to define entities in this article this time!)</p>
<p><img src="/assets/images/articles/2017/01/apiai-intents-02.png" alt="api.ai intents" /></p>
<p>Create some more contexts:</p>
<p><img src="/assets/images/articles/2017/01/apiai-intents-03.png" alt="api.ai intents" /></p>
<p>Then (1) scroll down to <strong>Action</strong>, and enter “weather”. You need this action name on your node code later. Then (2) at <strong>Response</strong>, enter a default response. Assuming a user ask about the weather without specifying a city, enter something like “Which city?”</p>
<p><img src="/assets/images/articles/2017/01/apiai-intents-04.png" alt="api.ai intents" /></p>
<p>Save the Intents, and go to <strong>Fulfillment</strong> from the menu. Enable the webhook, and enter the ngrok URL with a route, let’s call it <code class="language-plaintext highlighter-rouge">/ai</code> and Save:</p>
<p><img src="/assets/images/articles/2017/01/apiai-webhook.png" alt="api.ai intents" /></p>
<h4 id="using-the-3rd-party-api-to-look-up-the-weather">Using the 3rd Party API to Look Up the Weather</h4>
<p>Go to <a href="http://openweathermap.org/">Open Weather Map</a>, and sign up to get the API key. We are going to use the API to fetch a <a href="http://openweathermap.org/current">current weather data</a> for one location.</p>
<p>Let’s just use this REST API with a city name as a param (also, your API key and the temperature unit):</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">restUrl</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">http://api.openweathermap.org/data/2.5/weather?units=imperial&APPID=</span><span class="dl">'</span><span class="o">+</span><span class="nx">WEATHER_API_KEY</span><span class="o">+</span><span class="dl">'</span><span class="s1">&q=</span><span class="dl">'</span><span class="o">+</span><span class="nx">city</span><span class="p">;</span>
</code></pre></div></div>
<p>In your <code class="language-plaintext highlighter-rouge">webhook.js</code>, create another <code class="language-plaintext highlighter-rouge">POST</code> method route, <code class="language-plaintext highlighter-rouge">/ai</code>. Remember the action name you’ve specified with API.ai console earlier:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/ai</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">result</span><span class="p">.</span><span class="nx">action</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">weather</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">city</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">result</span><span class="p">.</span><span class="nx">parameters</span><span class="p">[</span><span class="dl">'</span><span class="s1">geo-city</span><span class="dl">'</span><span class="p">];</span>
<span class="kd">let</span> <span class="nx">restUrl</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">http://api.openweathermap.org/data/2.5/weather?APPID=</span><span class="dl">'</span><span class="o">+</span><span class="nx">WEATHER_API_KEY</span><span class="o">+</span><span class="dl">'</span><span class="s1">&q=</span><span class="dl">'</span><span class="o">+</span><span class="nx">city</span><span class="p">;</span>
<span class="nx">request</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">restUrl</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">body</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">err</span> <span class="o">&&</span> <span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">==</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">json</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">body</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">msg</span> <span class="o">=</span> <span class="nx">json</span><span class="p">.</span><span class="nx">weather</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">description</span> <span class="o">+</span> <span class="dl">'</span><span class="s1"> and the temperature is </span><span class="dl">'</span> <span class="o">+</span> <span class="nx">json</span><span class="p">.</span><span class="nx">main</span><span class="p">.</span><span class="nx">temp</span> <span class="o">+</span> <span class="dl">'</span><span class="s1"> ℉</span><span class="dl">'</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span>
<span class="na">speech</span><span class="p">:</span> <span class="nx">msg</span><span class="p">,</span>
<span class="na">displayText</span><span class="p">:</span> <span class="nx">msg</span><span class="p">,</span>
<span class="na">source</span><span class="p">:</span> <span class="dl">'</span><span class="s1">weather</span><span class="dl">'</span><span class="p">});</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">400</span><span class="p">).</span><span class="nx">json</span><span class="p">({</span>
<span class="na">status</span><span class="p">:</span> <span class="p">{</span>
<span class="na">code</span><span class="p">:</span> <span class="mi">400</span><span class="p">,</span>
<span class="na">errorType</span><span class="p">:</span> <span class="dl">'</span><span class="s1">I failed to look up the city name.</span><span class="dl">'</span><span class="p">}});</span>
<span class="p">}})</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Make sure to return is as JSON that api.ai will read from this webhook.</p>
<p>Let’s test your bot from Messenger:</p>
<p><img src="/assets/images/articles/2017/01/facebook-apiai-weather.gif" alt="FB Messenger weather bot" /></p>
<p>Yay, now you have your own Messenger bot that chats and answer weather info!</p>
<p>If you deploy your bot, make sure to change your webhook endpoints on both Facebook Developer app setting and API.ai Fulfillment.</p>
<p>I hope you enjoyed the article. Now you can tailor your intents, add more features, and use the training feature for better results to make your bot more interesting!</p>
<h3 id="by-the-way">By the way…</h3>
<p>I am currently working at <a href="https://nexmo.com">Nexmo</a> and we are working on the Chat API, which integrate multiple chat apps including Facebook, WeChat, LINE, etc. So if you have a business with customers from all over the world especially the countries like China where the Great Firewall prevents people to use Facebook, and if you’d like to set up a customer support chat system, you need to support something like WeChat too.</p>
<p>The Nexmo Chat API can connect multiple chat apps all together. Also there is the SMS API too. I will write about the Chat API soon on <a href="https://nexmo.com/blog">Nexmo Blog</a>!</p>
https://girliemac.com/blog/2016/10/24/slack-command-bot-nodejs2016-10-24T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p><img src="/assets/images/articles/2016/10/slack-httpstatuscats-icons.png" alt="Slack HTTP Status Cats icons" /></p>
<p>It was raining on a few weekends ago, instead of binge-watching some Netflix shows I decided to do some small project with the Conversational UI / Chatbot, and wrote the <a href="http://www.girliemac.com/slack-httpstatuscats/">HTTP Status Cats command for Slack</a>! Basically, I made my <a href="http://http.cat">HTTP cats</a> (that gave myself a 15 minutes of fame in 2011) into a slash command for <a href="https://slack.com">Slack</a>, where can simply type <code class="language-plaintext highlighter-rouge">/httpstatus</code> followed by a status code (e.g. <code class="language-plaintext highlighter-rouge">404</code>) on Slack chat and get the status description with the cat pics. </p>
<p><img src="http://www.girliemac.com/slack-httpstatuscats/public/images/slack-httpstatuscats.gif" alt="HTTP Status Cats Slack bot" /></p>
<p>Although I made some positive notes on its developer-friendliness of the <a href="https://api.slack.com">Slack’s API</a> docs in my <a href="https://medium.com/@girlie_mac/developer-experience-matters-8c4dcb8cc80#.j74b4p2iw">Developer Experiences Matters</a> article, I found it a bit confusing when I actually started developing along with the docs, because there are loaded with info and it is hard to find some resources I need. While developing I took notes of each step, so I decided to share how I have created the HTTP Status Cats command.</p>
<p>There are two parts. You can stop after the step 1 if you don’t wish to distribute your bot:</p>
<ol>
<li>Writing a slash command with Node.js and run it locally only on your team</li>
<li>Making it installable for public (so you can submit your bot to <a href="https://slack.com/apps">Slack’s App Directory</a> if you want)</li>
</ol>
<p>My step-by-step instruction uses Node.js, so if you’d like to follow the how-to, make sure <a href="https://nodejs.org">Node.js</a> is installed on your machine.</p>
<p><a href="https://github.com/girliemac/slack-httpstatuscats">The source code</a> and the <a href="http://www.girliemac.com/slack-httpstatuscats/">HTTP Status Cats command bot app</a> are both available on GitHub</p>
<h2 id="1-creating-your-private-slash-command">1. Creating Your Private Slash Command</h2>
<p>In Slack’s official term, what you are going to do is called <a href="https://api.slack.com/custom-integrations">Custom Integrations</a>. Before building what they call App, you need this dry-run on your chat room. If you don’t have your own test team account, <a href="https://slack.com/create">create one</a> to get started.</p>
<h3 id="configuring-your-slash-command">Configuring Your Slash Command</h3>
<p>Sign in to your Slack account and choose your command at <a href="https://my.slack.com/services/new/slash-commands">my.slack.com/services/new/slash-commands</a>. In my case, I entered <code class="language-plaintext highlighter-rouge">/httpstatus</code> and hit the <strong>Add Slash Command Integration</strong> button to go to the next page.</p>
<p>You will see the Outgoing payload data with a token etc, but you don’t need to worry about this in this moment. Just go ahead and fill out some of the fields.</p>
<p><img src="/assets/images/articles/2016/10/slack-config-custom-integration.png" alt="Slack config" /></p>
<p>You can skip most of the field for now, but you must enter the (1) Command, (2) URL, and make sure the (3) Method is POST.</p>
<p>Once you enter them correctly, you should see the “Your settings have been saved!” message on top of the screen for a few seconds.</p>
<p>For the <strong>URL</strong>, I am using a temporary URL from <a href="https://ngrok.com/">ngrok</a>, which serves my localhost to a public URL. You can probably just put your localhost URL such as <code class="language-plaintext highlighter-rouge">http://localhost:3000.</code></p>
<h4 id="optional-using-ngrok">Optional: Using ngrok</h4>
<p>If you wish to use ngrok for your development too, download ngrok from https://ngrok.com, run it on terminal:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ngrok http 3000
</code></pre></div></div>
<p><img src="/assets/images/articles/2016/10/ngrok.png" alt="ngrok" /></p>
<p>Now you’ve got a ngrok URLs for your local server. In this case, localhost:3000. In this case, copy this URL, http://71f03962.ngrok.io and paste it into the configuration setup.</p>
<h3 id="writing-the-response-with-nodejs">Writing the Response with Node.js</h3>
<p>How it works is that when a user trigger the slash command from Slack client’s interface, the message will be sent to the URL via <code class="language-plaintext highlighter-rouge">HTTP POST</code> (or <code class="language-plaintext highlighter-rouge">GET</code> if you specified in your config).</p>
<p>When you receive a request from your user, for instance, <code class="language-plaintext highlighter-rouge">/httpstatus 302</code>, the data that will be posted to your URL looks like:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">command</span><span class="o">=</span>/httpstatus
<span class="nv">text</span><span class="o">=</span>302
<span class="nv">response_url</span><span class="o">=</span>https://hooks.slack.com/commands/1234/5678
...
</code></pre></div></div>
<p>Your bot gives a response for the command, <code class="language-plaintext highlighter-rouge">/httpstatus 302</code> with an answer. In this case the bot will answer with the description of status code 302 with [a cat picture](https://http.cat/302.</p>
<p>Now. let’s write the response with Node.js using Express.</p>
<p>First, install Express.JS and body-parser (for POST):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>express body-parser <span class="nt">--save</span>
</code></pre></div></div>
<p>Create a <strong>index .js</strong> file, and instantiate express and listen the server to port 3000. Because you have set your ngrok to <code class="language-plaintext highlighter-rouge">localhost:3000</code>, you must use the same port!</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="dl">'</span><span class="s1">use strict</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">bodyParser</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">body-parser</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">bodyParser</span><span class="p">.</span><span class="nx">json</span><span class="p">());</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">bodyParser</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="na">extended</span><span class="p">:</span> <span class="kc">true</span> <span class="p">}));</span>
<span class="kd">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="err"> </span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Express server listening on port %d in %s mode</span><span class="dl">'</span><span class="p">,</span> <span class="nx">server</span><span class="p">.</span><span class="nx">address</span><span class="p">().</span><span class="nx">port</span><span class="p">,</span> <span class="nx">app</span><span class="p">.</span><span class="nx">settings</span><span class="p">.</span><span class="nx">env</span><span class="p">);});</span>
</code></pre></div></div>
<p>Now, create HTTP POST route method to handle the command:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">text</span><span class="p">;</span>
<span class="c1">// implement your bot here ...</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Here, you need to look for the value of <code class="language-plaintext highlighter-rouge">text</code>, which comes from a user. To create a HTTP Status bot, the query should be something like “404” for <code class="language-plaintext highlighter-rouge">/httpstatus</code> command. You should write some error-checking code to see if you’re getting a right value. If a user enter a wrong value, throw some error or send a message, for example, look only for a digit:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span><span class="p">(</span><span class="o">!</span> <span class="sr">/^</span><span class="se">\d</span><span class="sr">+$/</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">q</span><span class="p">.</span><span class="nx">text</span><span class="p">))</span> <span class="p">{</span> <span class="c1">// not a digit</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="dl">'</span><span class="s1">U R DOIN IT WRONG. Enter a status code like 200!</span><span class="dl">'</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This message is sent privately to the user who entered a command with an unexpected value.</p>
<p>If the value is what you expect, send a response in JSON:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">response_type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">in_channel</span><span class="dl">'</span><span class="p">,</span> <span class="c1">// public to the channel</span>
<span class="na">text</span><span class="p">:</span> <span class="dl">'</span><span class="s1">302: Found</span><span class="dl">'</span><span class="p">,</span>
<span class="na">attachments</span><span class="p">:[</span>
<span class="p">{</span>
<span class="na">image_url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://http.cat/302.jpg</span><span class="dl">'</span>
<span class="p">}</span>
<span class="p">]};</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
</code></pre></div></div>
<p>The answer to the correct command from the user will be displayed publicly by setting <code class="language-plaintext highlighter-rouge">response_type</code> as <code class="language-plaintext highlighter-rouge">in_channel</code> (The default type is <code class="language-plaintext highlighter-rouge">ephemeral</code>, sent as a private message).</p>
<p>This response will look like this on Slack:</p>
<p><img src="/assets/images/articles/2016/10/slack-command.png" alt="Slack command public message" /></p>
<p>In this example, I am using two parts in the response; (1) <code class="language-plaintext highlighter-rouge">text</code> and (2) <code class="language-plaintext highlighter-rouge">attachments</code>, which is an additional field displayed within the gray border, where I include an image.</p>
<p>Of course you can display text and change the border color in the attachment if you want. To customize the message format, see <a href="https://api.slack.com/docs/message-formatting">Basic message formatting</a> on Slack API docs.</p>
<p>Please note that in this code sample above, I hard-code the text and image URL, but in <a href="https://github.com/girliemac/slack-httpstatuscats">my actual code</a>, I keep all text strings in a separated file, and look it up if the user query matches. If not, display an error message privately.</p>
<p><img src="/assets/images/articles/2016/10/slack-command-private.png" alt="Slack command private message" /></p>
<p>Now, run the node code, then test your command on Slack client!</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>node index.js
</code></pre></div></div>
<p>If everything works fine on your private Slack chat, and you are happy as if, you’re done with the custom integration!</p>
<p>In the next step, you will handle the authentication and deploy the code. So if you want to distribute your command bot, read on!</p>
<h2 id="2-distributing-your-slack-bot">2. Distributing your Slack Bot</h2>
<p>To share your custom integration, you need to deploy the code and make it installable. To do so, you need to work on a few more things.</p>
<h3 id="setting-up-your-app">Setting up Your App</h3>
<p>Now you need to register for your app and get your API keys.</p>
<p>First, go to <a href="https://api.slack.com/apps">https://api.slack.com/apps</a>, and click the <strong>Create an App</strong> button.</p>
<p><img src="/assets/images/articles/2016/10/slack-create-app.png" alt="Slack Create App" /></p>
<p>You can fill out the rest of the form later. The App config may be a bit confusing because there are multiple parts (and you may not even notice everything first). For a slash command bot, you need to fill out at least these sections:</p>
<ul>
<li>Basic Information (at https://api.slack.com/apps/YOUR_APP_ID/general)</li>
<li>OAuth & Permissions (at …/YOUR_APP_ID/oauth)</li>
<li>Slash Commands (at …/YOUR_APP_ID/slash-commands)</li>
</ul>
<h4 id="keeping-your-credentials-in-env-file">Keeping Your Credentials in .env File</h4>
<p>Create <strong>.env</strong> file in the root of your app directory to keep your credentials (<strong>Client ID</strong>, <strong>Client secret</strong>, and <strong>Verification token</strong>) you can find at your app’s Basic Information section.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">SLACK_CLIENT_ID</span><span class="o">=</span>12345XXXXX.09876XXXXX
<span class="nv">SLACK_CLIENT_SECRET</span><span class="o">=</span>535d2f9....
<span class="nv">SLACK_VERIFICATION_TOKEN</span><span class="o">=</span>42P829U...
</code></pre></div></div>
<p>List the .env in your <strong>.gitignore</strong> file to keep out from public eyes when you push to git etc.</p>
<h4 id="using-foreman">Using Foreman</h4>
<p>To read the .env file from your app, I am using <a href="[https://coderwall.com/p/qdluuq/node-js-node-foreman](https://coderwall.com/p/qdluuq/node-js-node-foreman)">Node Foreman</a> (instead of <em>dotenv</em> module because it failed when deploying to Heroku).</p>
<p>You need to install it globally on your machine:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install</span> <span class="nt">-g</span> foreman
</code></pre></div></div>
<p>At the root of your app, create a file with name of <code class="language-plaintext highlighter-rouge">Procfile</code> and add this in the file:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">web</span><span class="p">:</span> <span class="nx">node</span> <span class="nx">index</span><span class="p">.</span><span class="nx">js</span>
</code></pre></div></div>
<p>When you run our node app, run with</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nf start
</code></pre></div></div>
<h3 id="authenticating-a-user">Authenticating a User</h3>
<p>Slack uses <a href="https://oauth.net/2/">OAuth 2.0</a> for a user authentication. You can read the <a href="https://api.slack.com/docs/oauth">grant flow</a> on the Slack doc, but you actually don’t need to implement the whole OAuth mechanism in your app when you use the <a href="https://api.slack.com/docs/slack-button">Slack Button</a> to authenticate your users. The diagram shows below shows what you need to do, and I took this from the Slack API doc and modified:</p>
<p><img src="/assets/images/articles/2016/10/slack-oauth.gif" alt="OAuth with Slack" /></p>
<p>Basically, what you are going to do are:</p>
<ol>
<li>Set up a web page with the button that passes some params to Slack. <em>(User: After clicking the button, Slack redirects the user to authenticate)</em>.</li>
<li>Your node app will receive a temporary <code class="language-plaintext highlighter-rouge">code</code> from Slack via <code class="language-plaintext highlighter-rouge">GET</code>. The temp code expires in 10 min.</li>
<li>Exchange the authorization code for an access token using the <a href="https://api.slack.com/methods/oauth.access"><code class="language-plaintext highlighter-rouge">oauth.access</code></a> API by <code class="language-plaintext highlighter-rouge">POST</code>ing. The auth process is done when your node app receives 200 OK. </li>
<li>Optionally, use the <code class="language-plaintext highlighter-rouge">token</code> to call another API to get the team name, so that you can redirect the user to the team URL, https://team-name.slack.com right after the auth is done.</li>
</ol>
<p>When I was reading the Slack docs, I didn’t notice there was a button generator on Slack API page, so I started implementing by myself with Passport (Node.js OAuth middleware). But later I realized that authentication with the button!</p>
<h4 id="setting-up-your-button">Setting up Your Button</h4>
<p>First, you need to set up a static web page. It can be a part of your node app, or separated. I made it independently from my node app, and host it on <a href="http://www.girliemac.com/slack-httpstatuscats/">GitHub Pages</a>.</p>
<p>Then go to <a href="https://api.slack.com/docs/slack-button">https://api.slack.com/docs/slack-button</a>, scroll to <strong>Add the Slack button</strong> to generate your button. Make sure to check <strong>Commands</strong> for the scope.</p>
<p><img src="/assets/images/articles/2016/10/slack-generate-button.png" alt="Slack button" /></p>
<p>If you want to do the optional API call to get the team info (step 4), you need to tweak the GET param in the auth URL.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><a</span> <span class="na">href=</span><span class="s">"https://slack.com/oauth/authorize?scope=commands+team%3Aread&client_id=your_client_id"</span><span class="nt">></span>
</code></pre></div></div>
<p>Notice the scope- along with <code class="language-plaintext highlighter-rouge">commands</code>, add <code class="language-plaintext highlighter-rouge">team:read</code> (Escape the <code class="language-plaintext highlighter-rouge">:</code> as <code class="language-plaintext highlighter-rouge">%3A</code>). You can learn more about <a href="https://api.slack.com/docs/oauth-scopes">OAuth scopes on the Slack API docs</a>.</p>
<p><img src="https://platform.slack-edge.com/img/add_to_slack.png" alt="Slack button" /></p>
<h4 id="issuing-token">Issuing Token</h4>
<p>Let’s use Express.js again to GET the temporary code (<code class="language-plaintext highlighter-rouge">req.query.code</code>) from Slack.</p>
<p>I am using <code class="language-plaintext highlighter-rouge">/slack</code> route. You can name whatever you want but make sure that you use the URL (Use your grok URL such as <em>http://71f03962.ngrok.io/slack</em> during development) as a <em>Redirect URL</em> at <strong>OAuth & Permissions</strong> at https://api.slack.com/apps/YOUR_APP_ID/oauth as a part of your App configuration.</p>
<p>Once you get the temp code, you need to POST the code along with your credentials to exchange the code for an access token.</p>
<p>To POST, I am using <code class="language-plaintext highlighter-rouge">request</code>, a HTTP request client for Node.js.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>request <span class="nt">--save</span>
</code></pre></div></div>
<p>Once installed, get the temp code via GET (from a user auth) for a token via POST using <code class="language-plaintext highlighter-rouge">auth.access</code> API:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">request</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/slack</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span>
<span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="p">{</span><span class="na">form</span><span class="p">:</span> <span class="p">{</span>
<span class="na">client_id</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">SLACK_CLIENT_ID</span><span class="p">,</span>
<span class="na">client_secret</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">SLACK_CLIENT_SECRET</span><span class="p">,</span>
<span class="na">code</span><span class="p">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">code</span>
<span class="p">}};</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://slack.com/api/oauth.access</span><span class="dl">'</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">body</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">error</span> <span class="o">&&</span> <span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">==</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// You are done.</span>
<span class="c1">// If you want to get team info, you need to get the token here</span>
<span class="kd">let</span> <span class="nx">token</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">body</span><span class="p">).</span><span class="nx">access_token</span><span class="p">;</span> <span class="c1">// Auth token</span>
<span class="p">}</span>
<span class="p">...</span>
</code></pre></div></div>
<h4 id="optional-redirecting-the-user-to-the-team-url">Optional: Redirecting the User to the Team URL</h4>
<p>Once the auth is done, you are done. However, I wanted to give a slightly better UX by redirecting the user to the chat room, instead of dumping the user right there like I’ve seen in many 3rd party Slack apps.</p>
<p>To obtain the team name (as a part of the chat room URL), use <a href="https://api.slack.com/methods/team.info"><code class="language-plaintext highlighter-rouge">team.info</code></a> API.</p>
<p>Add this where you got the access token in the code sample above:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">...</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://slack.com/api/team.info</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span><span class="na">form</span><span class="p">:</span> <span class="p">{</span><span class="na">token</span><span class="p">:</span> <span class="nx">token</span><span class="p">}},</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">body</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">error</span> <span class="o">&&</span> <span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">==</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">team</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">body</span><span class="p">).</span><span class="nx">team</span><span class="p">.</span><span class="nx">domain</span><span class="p">;</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://</span><span class="dl">'</span> <span class="o">+</span><span class="nx">team</span><span class="o">+</span> <span class="dl">'</span><span class="s1">.slack.com</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre></div></div>
<p>You need to use the access token to be able to access the API. Once successfully done, the API returns the user’s team info including the team name (<code class="language-plaintext highlighter-rouge">team.domain</code>), so use it to redirect the user to the team chat room URL.</p>
<p>Ta-da! Now your user should be re-directed to a right place!</p>
<p>For this article, I simplified all my code, but check out <a href="https://github.com/girliemac/slack-httpstatuscats">the entire code on GitHub</a> to see all the error handlings and when to use <em>Verification token</em> for your app.</p>
<h3 id="deploying-to-server">Deploying to Server</h3>
<p>Of course, you can deploy wherever you want. But if you want to deploy to Heroku like I did, I found <a href="https://blog.heroku.com/how-to-deploy-your-slack-bots-to-heroku">this article by Heroku</a> helpful.</p>
<p>Make sure to set up your env vars (where you set in your .env file) with the <code class="language-plaintext highlighter-rouge">heroku config</code> command such as <code class="language-plaintext highlighter-rouge">heroku config:set API_KEY=123</code></p>
<p>Once you are done with the deployment, go back to your Slack App setting page to change the <strong>OAuth & Permission</strong> URL from your ngrok URL to the Heroku URL.</p>
<p>As you see, writing a Slack slash command itself is easy, but to figuring out the whole process to make the bot available to everybody was a bit pain for me. I spent most of my time reading the docs to just figuring out, and spend far less for coding.</p>
<p>So I hope my writing was helpful for you.</p>
<p><img src="/assets/images/articles/2016/10/slack-worked.png" alt="Hurray" /></p>
https://girliemac.com/blog/2016/08/16/developer-experience-matters2016-08-16T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p><em>I am writing this article based on the short talk I gave at <a href="http://www.devrelsummit.com/">DevRel Summit</a> in Seattle, and it is aimed for my fellow developer advocates, platform engineers, product managers, and CTOs, who work for companies that provide developer platforms, APIs etc. also anybody who advocate their own software / libraries / frameworks</em></p>
<hr />
<p><img src="/assets/images/articles/2016/08/dx-jamie-comic.jpg" alt="Developer Experience Matters" /></p>
<p>Let’s say, you are working for a company that provides public APIs, or you are an open-source JavaScript library author, who want to attract developers out there to use your products.</p>
<p>When your potential developers, who are in search for a solution for a new project- this can be a large-scale commercial project, or it could be to compete at a hackathon, see your shiny website but has very poorly-designed developer portal (or your open-source project on GitHub may have some stars, but with no README), how does the developer feel? Do they still want to try it out anyway, or keep searching something else and end up choosing your competitor?</p>
<p>I have been working as a developer evangelist, or related positions in Developer Relations for about six years for three (technically four, including acquisition) different companies, to advocate both proprietary and open technologies. From the experiences, what I’ve seen is that developers (including myself) tend to shy away when the API (or platform, services, etc.) is poorly designed, lacks good docs, Get Started guide, or code samples.</p>
<p>This <strong>Developer Experience</strong> is one of the biggest key factors for developers to decide if they use certain technologies to use.</p>
<h2 id="user-experience-and-developer-experience">User Experience and Developer Experience</h2>
<p>Before becoming a developer evangelist, I was working as a developer in Human Interface team for <strong>Palm webOS</strong> mobile platform. Although we didn’t successfully dominate the market, what the team has designed has been inherited to present-era iOS and Android. For example, non-intrusive visual notification system, card views, universal search bar, etc.</p>
<p>My then-teammates has influenced me so much, and it has affected my career and the way of thinking. Since then, I care <strong>usability</strong> and <strong>user-experiences (UX)</strong> for everything - not only software and hardware interface designs, but for coding styles, APIs, and documentations, because I believe UX is also applied to developers, when your <em>users</em> are developers.</p>
<p>According to <a href="https://usability.org">usabilty.gov</a>,</p>
<blockquote>
<p>User-Experience (UX) focuses on having a deep understanding of users, what they need, what they value, their abilities, and also their limitations.</p>
</blockquote>
<p>and I think the statement is still true, when you swap out the word, <em>user</em> to <em>developer</em>:</p>
<blockquote>
<p>Developer-Experience (DX) focuses on having a deep understanding of developers, what they need, what they value, their abilities, and also their limitations.</p>
</blockquote>
<p>Yes, I am suggesting Developer Experience <em>is</em> a type of User Experience!</p>
<h3 id="bad-developer-experience-and-frustrations">Bad Developer Experience and Frustrations</h3>
<p>This is a good example of how not to design- At a gas station, you’ve got a gas pump looks like this, how do you react?</p>
<p><img src="/assets/images/articles/2016/08/gas-pump.jpg" alt="Local Gas Pump by Jared Spool" /></p>
<p><em>(Photo credit: https://flic.kr/p/5ckBZq by Jared Spool. CC-BY-SA)</em></p>
<p>Typically, when a user face such bad user experience, the reactions would be:</p>
<ol>
<li>Get confused</li>
<li>Make a good guess and fail</li>
<li>Frustrated</li>
<li>Repeat 2 - 3</li>
<li>Totally pissed off</li>
</ol>
<p>How about if you provide very enigmatic API, sans proper documentations or tutorial, and a developer is trying to figure out how to use the API- How does the developer react?</p>
<p>I think the reactions would be the same as above! The difference is that if you are at a gas station, you are more likely to try again or ask somebody to get your car filled up, while developers are more likely to google around (or ask Twitter followers) then ditch your service for use your competitor’s over the bad developer experiences.</p>
<h2 id="developer-centric-products">Developer-Centric Products</h2>
<p>So, what kinds of products have users who are developers? I tried to come up with a list of “products” that we need to care about developer experience-</p>
<ul>
<li>Platforms</li>
<li>SDKs & tools</li>
<li>APIs</li>
<li>Developer website UI/UX, and contents</li>
<li>Docs, tutorials, and “Get started” guides</li>
<li>Samples on GitHub - code & README</li>
</ul>
<p>While developer evangelists have works including developer trainings including workshops and conferences, and events like hackathons, here, I only try to define products, and excluding all the direct actions and interaction with developers.</p>
<h3 id="api-designing">API Designing</h3>
<p>API providers do also need to provide SDKs for common / high-demand languages, and sometimes for frameworks. You are losing developers when either SDK or API, as user-interface for developers, are missing.</p>
<p>Also, good API should be intuitive and easy to use, and bad API includes bad naming conventions, bad error messages, inconsistencies, etc. <a href="https://www.youtube.com/watch?v=aAb7hSCtvGw">In his talk, Joshua Bloch stated</a> that:</p>
<ul>
<li>API can be among a company’s greatest assets</li>
<li>Can also be among company’s greatest liabilities</li>
<li>Public APIs are forever</li>
</ul>
<p>He also tells us to <em>document religiously</em>- good API must have good design and documentation. I am not going to summarize all his talks here, so I recommend you should watch the <a href="(https://www.youtube.com/watch?v=aAb7hSCtvGw)">video</a> by yourself.</p>
<h3 id="api-documentations">API Documentations</h3>
<p>When we are talking about API docs, actually we need to provide more than just API references. Developers expect:</p>
<ul>
<li>Reference documentations</li>
<li>Getting Started guide</li>
<li>Tutorials</li>
</ul>
<p>While API reference explains every call in the API and parameter, values, etc., other types of docs often provides step-by-step instructions, and copy-and-pasteable code samples, including <em>Hello World</em>.</p>
<p>A rule of thumb of writing these docs is keep everything simple in plain English. Complex docs don’t impress your fellow engineers, but rather repel them. The basic tutorial should be short and simple too, but if you want to explore your creativity like I do, you should provide supplemental tutorials beyond your API docs- Blog, Demo, Showcase, etc.</p>
<h3 id="creative-contents-for-developers">Creative Contents for Developers</h3>
<p>My expertise is providing interesting use cases with code samples and demos. (You can browse my articles on this blog and many other sites!) What I knew and what I’ve learned from my own experiences are that developer experience is good when a doc has these:</p>
<h4 id="meaningful-diagrams">Meaningful Diagrams</h4>
<p>A picture is worth a thousand words - a simple diagram can explain complex idea far better. When I was writing about push notifications gateway for GCM and APNs, I decided to create a diagram to show how it works, rather than writing the whole explanations, and it turns out my readers (and coworkers) really did understand what the device registration meant, and how it works with push notification.</p>
<p>This is an actual screenshot of the blog I wrote for my previous employer, PubNub:</p>
<p><img src="/assets/images/articles/2016/08/screenshot-gcm.png" alt="screenshot of my blog" /></p>
<h4 id="screen-captures">Screen Captures</h4>
<p>A step-by-step instruction in a bullet list helps your developers for sure, but I found they love when the steps are described with actual screenshots. And devs love even more when they are in a single gif animation, which I think is a great example of the <em>TL;DR</em> principal!</p>
<p>This example below is what I created to show hoe to use Chrome DevTools Device Mode. I created for <a href="http://www.girliemac.com/blog/2014/07/28/devicemode/">my own blog</a>, and, later adopted by Google’s Chrome team, and stayed on the official doc for a while.</p>
<p><img src="/assets/images/articles/2014/07/devtools-device-mode-2.gif" alt="screenshot of devtools" /></p>
<h4 id="video-tutorials">Video Tutorials</h4>
<p>Especially, when you are targeting the first-timers, I found video tutorials are quite effective, because N00bs may have no idea where to get started. I don’t blame on them because there is always a first time for everybody.</p>
<p>I created <a href="https://www.youtube.com/watch?v=sC72DCxQrcU">this Johnny-Five video</a> because I was asked by enough numbers of people where to get started with hardware. The tutorial is tageting Node.js engineers who has no prior experiences with hardware engineering. I show electrical parts and explain what they are and how to wire. A cool thing is that the tutorial was introduced on <a href="https://arduino.cc">Arduino</a> official blog, and got a lot of good feedbacks on social media.</p>
<h4 id="more-improvement-for-better-dx">More Improvement for Better DX</h4>
<p>There are more things I try to keep in mind for good DX-</p>
<ul>
<li>Publish date should be included, especially because a dev year is like a dog year, where things get outdated pretty quick.</li>
<li>No pushy marketing- obnoxious “Sign up now!!!” buttons and popups annoy devs away.</li>
<li>Docs and tuts need to have good browsing experiences just like web pages. Always link to references and related pages.</li>
<li>Don’t PDF everything. Docs and tuts for developers are not white papers.</li>
<li>Provide a place for feedbacks- my last company’s marketing peeps refused to add a comment section on blog, or set up a forum, so in the results, I got comments and questions on random social media everywhere, and my email addresses (work, personal, and wrongly-guessed work email address that eventually forwarded to me.)</li>
<li>Cut the BS- if your API is not ready or buggy, state so honestly.</li>
</ul>
<h2 id="developer-friendliness">Developer-Friendliness</h2>
<p>I stumbled upon this tweet about user-friendliness on the other day-</p>
<p><img src="/assets/images/articles/2016/08/kaz-tweet.png" alt="screenshot of devtools" /></p>
<p>It is interesting to see how the two companies describe the same errors in such different languages.</p>
<p>I was curious how these companies differ in Developer Experience, so I took a look at their API docs, and the results were not surprising. I am pretty sure the product peeps (who worked on the messages) at JIRA and Slack don’t work for the API docs, however the the friendliness of these docs reflect exactly like-</p>
<p>These are documentations for their OAuth authentication-</p>
<p><a href="https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-oauth-authentication">JIRA</a>:</p>
<p><img src="/assets/images/articles/2016/08/jira-doc.png" alt="JIRA OAuth Doc" /></p>
<p><a href="https://api.slack.com/docs/oauth">Slack</a>:</p>
<p><img src="/assets/images/articles/2016/08/slack-doc.png" alt="Slack OAuth Doc" /></p>
<p>This is pretty clear that Slack docs is far more developer-friendly, not because of the cute robot, but the non-authoritative tone, and the way they introduce OAuth (what it is, and how it works) and the diagram, while JIRA doc doesn’t even bother explaining what OAuth is, as if newbie developers are not welcomed.</p>
<p>I wonder if it is more “appropriate” for enterprise companies to be unfriednly to both user and developer…</p>
<h2 id="knowing-your-developers">Knowing Your Developers</h2>
<p>If you interact directly with developers on chat or forum, or work with community managers who do, you probably already have good idea about your developer community.</p>
<p>Another method I adopted from Human Interface team was defining <strong><a href="https://en.wikipedia.org/wiki/Persona_(user_experience)">persona</a></strong> during product development process. In my case, of course it is developer personas. I gather information from registrations, surveys, Stackoverflow, and support team (e.g. What language/SDK a developer use? What kinds of apps they develop?) Also, I get info from sales reps and business development team about actual customer (e.g. size of a client’s company, industry, location, etc.)</p>
<p>I sometimes conduct brainstormings. This is quite effective to generate creative ideas and solutions, as well as team building. I combine the persona and brainstorming to figure our what our developers want.</p>
<p><img src="/assets/images/articles/2016/08/dx-brainstorm.jpg" alt="brainstorming" /></p>
<p>This photo was taken right after the first brainstorming session was done at my previous work. After the session, we sorted the ideas in category and feasibility.</p>
<p>Sure, this does not look like your typical Developer Relations meeting, but I have successfully delivered a lot of good use-cases and tutorials and articles around them. After social media has picked up, the awareness of the virtually unknown company and the products went up.</p>
<h2 id="diversity-and-inclusiveness">Diversity and Inclusiveness</h2>
<p>The majority of developers may be male and understand English, but if you are targeting only the majority, you are still missing out large numbers developers out there.</p>
<p>Inclusivity typically means not to exclude any groups of gender (expression), race, ethnicity, disability, sexual orientation, etc. I am not going to talk too much about the importance of diversity in a workplace in this article, however, I strongly believe when you work at a diverse team, you can definitely reach out more developers, especially because people in general tend to trust somebody who they feel related to. In fact, many of my “fans” are minorities- women, immigrants, speaking English as a second language, etc. (It is very flattering when people tell/tweet/email me they are fan of my works!)</p>
<p>Especially when somebody in your team speak/write something other than English, it would be a huge advantage. I do speak and write Japanese fluently, and in numerous occasions, I have helped sales and other teams when the companies have Japanese clients. I have written blog posts, and spoken at conferences in Tokyo as well. My conference videos and slides on <a href="https://slideshare.net">Slideshare</a> have reached out far larger audiences. I can clearly tell you that it’s not easy for you to get into Asian markets without somebody who knows the languages and cultures well!</p>
<p>Even if your team has no other multi-lingual people or simple has no time to translate, when your organization has successfully support international developers, the community helps you.</p>
<p>For example, <a href="https://dev.opera.com">Dev.Opera</a> publishes their tech blog under Creative Commons, and open-sourced the contents on <a href="https://github.com/operasoftware/devopera">GitHub</a>, where their community can contribute. I have written <a href="https://dev.opera.com/articles/web-notifications-pubnub/">an article in English</a> for Dev.Opera, and the community member has translated it <a href="https://dev.opera.com/articles/ru/web-notifications-pubnub/">in Russian</a>! How awesome is it!</p>
<p><img src="/assets/images/articles/2016/08/devopera-russian.png" alt="translated in Russian" /></p>
<p>It is not easy to acquire fans worldwide, but having a diverse team makes it far easier.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Developer Experiences <em>really</em> matters!</p>
<p>Here’s the slide deck from <a href="http://www.devrelsummit.com/">DevRel Summit</a> :</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/CdP2J9ci1BP5Gq" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""> </iframe>
<h2 id="epilogue">Epilogue</h2>
<p>Despite my tireless efforts and successful outcomes, my principles of developer evangelism did not align with my former employer’s marketing department that controls the team. When somebody doesn’t care about developers, you have no job there. Well, it has been fun leading the team for a while!</p>
<p>I am joining a company who truly embraces developer experience, so you will hear from me about my new gig pretty soon!</p>
https://girliemac.com/blog/2016/07/30/arduino-johnny-five-1012016-07-30T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p>Since I started talking about hardware hacking with JavaScript at events and conferences, I have been constantly asked by fellow JavaScript engineers where to get started.</p>
<p>It is easy once you know how, but starting something new is always difficult, or more like, you won’t even want to try unless somebody shows you how. So I decided to create a video series to walk through.</p>
<p>Especially because I already have written some tutorials and published as my day job, including <a href="http://code.tutsplus.com/tutorials/how-to-create-a-smart-device-with-arduino-and-nodejs-using-pubnub--cms-25508">“How to Create a Smart Device With Arduino and Node.js Using PubNub”</a>, I wanted to film the video version. Although there was some conflicts with marketing team at work (I will talk about it sometimes…), I secretly did this side project with help pf my colleague, Eric, and made two videos.</p>
<p>Eventually, it was picked up by <a href="https://arduino.cc">Arduino.cc </a> blog, so we have proven that creating contents that target indie devs aren’t bad idea at all. It is rather sad when people think supporting “hobbyists” is wasting company money and resources.</p>
<p>Anyway, this is Part Uno of my video tutorial, where you can learn how to use Johnny-Five with Arduino, also learn about the basics of wiring and how to blink an LED in 10 minutes!</p>
<iframe src="https://player.vimeo.com/video/170236455" width="640" height="360" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
https://girliemac.com/blog/2016/06/13/kittycam-update-with-raspberrypi32016-06-13T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p>I was excited when <strong>Raspberry Pi 3</strong> came out earlier this year. According to <a href="https://www.raspberrypi.org/products/raspberry-pi-3-model-b/">raspberrypi.org</a>, this 3rd generation Pi has faster CPU, WiFi, and Bluetooth 41. and BLE, additional to the previous model.</p>
<p>So I decided to upgrade <a href="http://www.girliemac.com/blog/2015/12/25/kittycam-raspberrypi-camera-cat-face-recog-nodejs/">KittyCam</a>, a cat camera app built with my Raspberry Pi + Node.js project, which and I blogged about a while ago.</p>
<p>At that time, I was using the older Node v0.12.x (pre-IO.js, which I almost forgot about it happened after merged back with Node.js), so I decided to upgrade everything.</p>
<h2 id="install-the-latest-raspbian">Install the Latest Raspbian</h2>
<p>Since I got a brand-new Pi3, I install everything fresh, so instead of swapping the SD card from the old Pi, I installed the latest Raspbian build.</p>
<p>Forst, I download the latest <strong>Raspbian Jesse</strong> from <a href="https://www.raspberrypi.org/downloads/raspbian/">raspberrypi.org</a> to my Mac, then install it in a micro SD card using these <a href="https://www.raspberrypi.org/documentation/installation/installing-images/README.md">instructions</a> using <code class="language-plaintext highlighter-rouge">dd</code> tool.</p>
<p>In case you are also a MacBook Air user and don’t know, your MacBook has a SD card slot on the right hand side. But you will need an adapter.</p>
<p><img src="/assets/images/articles/2016/06/sdcard.jpg" alt="SD card adapter" /></p>
<p>The image is from <a href="(https://learn.sparkfun.com/tutorials/sd-cards-and-writing-images)">“SD Cards and Writing Images”</a> by Sparkfun (<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">CC BY-NC-SA 3.0</a>).</p>
<h2 id="installing-node-4">Installing Node 4</h2>
<p>Last time with Node 0.12, I used the 3rd party <a href="http://node-arm.herokuapp.com/">node-arm</a> to install it, but now ARM version is officially supported on <a href="https://nodejs.org/">nodejs.org</a>.</p>
<p>So you can just open up a browser in Raspbian, and download from <a href="https://nodejs.org/en/download/">nodejs.org Download page</a>:</p>
<p>Scroll the page down to <strong>Additional Platforms</strong> and choose ARMv7 (Note: I think ARMv8 works too, but I installed v7).</p>
<p><img src="/assets/images/articles/2016/06/raspi3-node4-armv7.png" alt="node download" /></p>
<p>or download and install on terminal as I did:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>wget https://nodejs.org/dist/v4.4.5/node-v4.4.5-linux-armv7l.tar.xz
<span class="nv">$ </span><span class="nb">tar</span> <span class="nt">-xvf</span> node-v4.4.5-linux-armv7l.tar.xz
<span class="nv">$ </span><span class="nb">cd </span>node-v4.4.5-linux-armv7l
<span class="nv">$ </span><span class="nb">sudo cp</span> <span class="nt">-R</span> <span class="k">*</span> /usr/local/
</code></pre></div></div>
<p>Check if Node is successfully installed by checking its version:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>node <span class="nt">-v</span>
</code></pre></div></div>
<p>If you wish, upgrade <strong>npm</strong> to v3 too.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install</span> <span class="nt">-g</span> npm3
</code></pre></div></div>
<h2 id="installing-updated-dependencies-for-kittycam">Installing Updated Dependencies for KittyCam</h2>
<p>Create a <code class="language-plaintext highlighter-rouge">KittyCam</code> directory and copy everything except <code class="language-plaintext highlighter-rouge">package.json</code>from <a href="https://github.com/girliemac/RPi-KittyCam">KittyCam repo</a>. But also keep the <code class="language-plaintext highlighter-rouge">node_modules/kittydar</code> because installing kittydar using npm, and use it as is will fail, when you install Node-Canvas. (or tweak kittydar’s <code class="language-plaintext highlighter-rouge">package.json</code> manually!)</p>
<h3 id="installing-cairo">Installing Cairo</h3>
<p>Get <strong>Cairo</strong> on your Raspbian bore installing Node-Canvas:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++
</code></pre></div></div>
<p>Once set up with Cairo, in KittyCam dir,</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>canvas
</code></pre></div></div>
<h3 id="installing-johnny-five">Installing Johnny-Five</h3>
<p>Also, since the last time I created KittyCam, <a href="http://johnny-five.io/">Johnny-Five</a> and the IO-plugin for Raspberry Pi, <a href="https://github.com/bryan-m-hughes/raspi-io">Raspi-io</a> have been upgraded a lot too. So just install the latest manually:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>johnny-five <span class="nt">--save</span>
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>raspi-io <span class="nt">--save</span>
</code></pre></div></div>
<h3 id="installing-all-other-node-modules">Installing All other Node Modules</h3>
<p>and all other node modules used for KittyCam. In the app, I am also using Cloudinary and PubNub. You can install both with npm too.</p>
<h2 id="hardware-wiring">Hardware Wiring</h2>
<p>I have not updated any hardware besides Pi.</p>
<p>When you hook up with a camera, make sure to enable the camera module from the <strong>Pi Software Config Tool</strong>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>raspi-config
</code></pre></div></div>
<p>Now, everything should work with Raspberry Pi 3!</p>
<p>I had chance to test it out while I was taking care of my friends’ cats!</p>
<p><img src="/assets/images/articles/2016/06/qateam.png" alt="QA Team" /></p>
<p>I have given the talk about KittyCam in a few conferences and meetups so far, such as NodePDX in Portland and ForwardJS in San Francisco. My slide deck is available on <a href="http://www.slideshare.net/tomomi/nodepdx-from-software-to-hardware-how-do-i-track-my-cat-with-javascript">SlideShare</a>!</p>
https://girliemac.com/blog/2015/12/25/kittycam-raspberrypi-camera-cat-face-recog-nodejs2015-12-25T00:00:00-08:00Tomomi Imurahttps://girliemac.com<p><img src="https://lh3.googleusercontent.com/UuKlrNQWs5wFciRqI8qiZKTVoh4XrTBa40LD5mUa5MIn=w1346-h757-no" alt="RPi KittyCam" title="Rapsberry Pi KittyCam" /></p>
<p>Ho, ho, ho! This is an overdue blog post for <a href="https://github.com/girliemac/RPi-KittyCam">the project</a> I’ve worked on during summer!</p>
<p>Last August, I created this Raspberry Pi app using a camera and PIR motion sensor, written in Node.js with helps with <strong>Johnny-Five</strong> and <strong>KittyDar</strong>. As I promised on the README file of the GitHub repo, I am finally writing the detailed instruction of how I built hardware and wrote the app.</p>
<p><img src="/assets/images/articles/2015/12/youtube-kittycam-thumb.jpg" alt="KittyCam on YouTube" title="YouTube" />
<a href="https://www.youtube.com/watch?v=wqewhjhjaHY">Watch the demo on YouTube :-)</a></p>
<h2 id="how-kittycam-works">How KittyCam Works</h2>
<p>The software is written in Node.js, simply because JavaScript is the language I am most comfortable with, also it is fun!</p>
<p>This is the basic flow:</p>
<ol>
<li>Detect motion (Use Johnny-Five IR.Motion obj)</li>
<li>Take photos (Raspistill, command line tool)</li>
<li>Cat facial detection (KittyDar)</li>
<li>Store the photos in cloud storage (Cloudinary)</li>
<li>Publish the data (URL) to PubNub for realtime streaming</li>
<li>Stream on web (subscribe the data from PubNub)</li>
</ol>
<p><img src="/assets/images/articles/2015/12/kittyCam-app.png" alt="KittyCam flow" title="KittyCam flow" /></p>
<p>The hardware-software communication is done with <a href="http://johnny-five.io/">Johnny-Five</a>, open-source JavaScript robotics programming framework. I am using it to talk with a PIR sensor. When the sensor detect my cat (or any moving objects) nearby Raspberry Pi, it triggers the camera.</p>
<p>Photos are taken using <code class="language-plaintext highlighter-rouge">raspistill</code> command line. One cool thing about Node.js is that you can execute commands by spawning child processes.</p>
<p>Once a photo is taken, I am using another child process to detect if any cats are on the photo, using <a href="https://github.com/harthur/kittydar">KittyDar</a>, an open source face detection for cats, written by Heather Arthur.</p>
<p>Additionally, I am sending the photos (only photos with cats) to a cloud storage, and at the same time, I stream the photo to web browser using <a href="http://pubnub.com">PubNub</a>, because I work for the company!</p>
<p>Now, let’s build your own!</p>
<h2 id="building-the-circuit-with-raspberry-pi-2">Building the Circuit with Raspberry Pi 2</h2>
<h3 id="what-you-need">What you need</h3>
<p>First, you need to get some hardware along with Raspberry Pi 2. I don’t recommend any older Raspberry Pi, as their memory is too low to run some code.</p>
<p>The Pi needs to be pre-installed with <strong>Raspbian OS</strong>. And if you are starting from a scratch, with Raspberry Pi fresh out of box, you can take a look at <a href="https://github.com/pubnub/workshop-raspberrypi"><strong>Setting up Raspberry Pi</strong> section of the instruction I wrote for my workshop</a> I give at conferences sometimes.</p>
<p>But if you are a newbie, I recommend to buy your first Pi from <a href="http://www.amazon.com/gp/product/B008XVAVAW/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B008XVAVAW&linkCode=as2&tag=girliemac-20&linkId=DU2AO5J5GTPAQMPO">CanaKit</a>, so you don’t need to set it up all by yourself.</p>
<p><img src="/assets/images/articles/2015/12/what-you-need-raspberry-pi.jpg" alt="What you need and how to assemble" title="The stuff you need and how to assemble" /></p>
<ol>
<li>Raspberry Pi 2 (with WiFi adapter) (<a href="http://amzn.to/1rk3VZY">buy</a>)</li>
<li>5MP Camera Board Module (<a href="http://amzn.to/1UKaEXl">buy</a>)</li>
<li>Pyroelectric Infrared (PIR) motion sensor (<a href="http://amzn.to/1ZJ3Nir">buy</a>)</li>
<li>3 Female/Female wires (<a href="http://amzn.to/1U8ajAZ">buy</a>)</li>
<li>Optional: LEGO compatible SmartiPi w/ camera case (<a href="http://amzn.to/28vkhAR">buy</a>)</li>
</ol>
<h3 id="assembling-hardware">Assembling Hardware</h3>
<p>This doesn’t require much of wiring. You can connect a camera and a PIR sensor directory to a Pi without any breadboards or soldering, as you see in the photo above at the previous section, or this Fritzing diagram below.</p>
<p><img src="/assets/images/articles/2015/12/pi-pir-camera_bb.png" alt="RPi KittyCam" title="Assemble PIR and camera" /></p>
<h4 id="camera-to-pi">Camera to Pi</h4>
<ul>
<li>Connect the camera module to the CSI port. See <a href="https://www.raspberrypi.org/help/camera-module-setup/">the video instruction of how to set up th camera module on RaspberryPi.org</a>.</li>
</ul>
<h4 id="pir-sensor-to-pi">PIR Sensor to Pi</h4>
<ul>
<li>1 red wire: PIR-VCC to Pi’s <strong>5V</strong> pin</li>
<li>1 black wire: PIR-GND to Pi’s ground (<strong>GND</strong> pin)</li>
<li>1 whatever color wire (brown in the photo): PIR-OUT to Pi’s Pin <strong>7</strong> (GPIO 4)</li>
</ul>
<p>The photo below is my Pi enclosed in SmartiPi case:
<img src="https://lh3.googleusercontent.com/o-XG7ZijXM_UXQHuYrDxC6mlTofyUzUCmHqNmr6oRYZk=w1346-h757-no" alt="RPi KittyCam" title="Rapsberry Pi KittyCam" /></p>
<h2 id="working-remotely-from-mac">Working Remotely from Mac</h2>
<p>You can plug in a monitor, keyboard, mouse, etc to your Pi and work directly on Raspbian GUI, or work from you Mac, like I usually do. This is how I work remotely on Mac:</p>
<h3 id="ssh-ing-into-raspberry-pi">SSH-ing into Raspberry Pi</h3>
<p>First, make sure your Pi and computer are on the same WiFi network.</p>
<p>If you are directly connecting your Pi to a monitor and a keyboard, open a terminal, and find the IP address:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pi@raspberrypi ~<span class="nv">$ </span><span class="nb">hostname</span> <span class="nt">-I</span>
</code></pre></div></div>
<p>Or use some IP scanner app on Mac, like <a href="http://angryip.org/download/#mac">Angry IP Scanner</a> to scan all connected devices.</p>
<p>Once you find the IP address, open a terminal app on Mac, and ssh into the address. I am using the default username for Pi, “pi”.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tomomi@Mac ~<span class="nv">$ </span>ssh pi@10.0.1.13
</code></pre></div></div>
<p>Then type the password. Default is “raspberry”.</p>
<p>Once connected to your Pi, you can create files, code, and execute from the terminal. Raspbian is a Debian based, so you can use usual linux commands.</p>
<h3 id="coding-on-your-fave-ide-on-mac">Coding on Your Fave IDE on Mac</h3>
<p>I usually use <strong>Sublime Text</strong> to code, so I prefer doing so for coding on Pi as well.
Here’s what I do:</p>
<p>First, download and install <a href="https://cyberduck.io">Cyberduck</a> on Mac.</p>
<p>Then connect your Pi via SSH, using its IP address (See the screenshot below)
<img src="/assets/images/articles/2015/12/cyberduck-connect-rpi.png" alt="Cyberduck to RPi" title="Connect Rapsberry Pi via Cyberduck" /></p>
<p>When you edit a file, open the file with “Edit”.
<img src="/assets/images/articles/2015/12/cyberduck-connect-rpi-edit.png" alt="Cyberduck to RPi" title="Connect Rapsberry Pi via Cyberduck" /></p>
<p>In my case, it automatically select Sublime to edit JavaScript files.</p>
<h2 id="software-setup">Software Setup</h2>
<h3 id="1-install-nodejs-in-your-raspberry-pi">1. Install node.js in your Raspberry Pi</h3>
<p>Make sure your Pi is up-to-date!</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>apt-get update
</code></pre></div></div>
<p>then</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>apt-get upgrade
</code></pre></div></div>
<h4 id="download-and-install">Download and Install</h4>
<p>Let’s download node from <a href="http://node-arm.herokuapp.com/">node-arm</a>, which is probably the easiest way:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>wget http://node-arm.herokuapp.com/node_archive_armhf.deb
</code></pre></div></div>
<p>and install the package:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>dpkg <span class="nt">-i</span> node_archive_armhf.deb
</code></pre></div></div>
<p>Check if node is successfully installed.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>node <span class="nt">-v</span>
</code></pre></div></div>
<p>As of Dec. 2015, the archive should install Node v0.12.6. This is the version I used and works fine for sure.</p>
<h3 id="2-enable-camera-access">2. Enable Camera Access</h3>
<p>To be able to use a hardware camera module with your Pi, you need to enable the software first.</p>
<p>Go to <strong>Pi Software Config Tool</strong> menu from a terminal:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>raspi-config
</code></pre></div></div>
<p>You should see the menu like this. Use arrow keys to select <strong>Enable Camera</strong>.</p>
<p><img src="/assets/images/articles/2015/12/config-enable-pi-camera.png" alt="Pi Software Config Tool" title="Pi Software Config Tool" /></p>
<p>Hit Return, then at the next screen, select <strong>Enable</strong>.</p>
<p>Test if your camera is working by try typing this command on terminal:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>raspistill <span class="nt">-o</span> photo.jpg
</code></pre></div></div>
<h2 id="installing-dependencies">Installing Dependencies</h2>
<p>If you wish to run the code from my GitHub repo, clone <a href="https://github.com/girliemac/RPi-KittyCam">RPi-KittyCam repo on GitHub</a>, and copy them over on Raspberry Pi.</p>
<p>It would be really nice if <code class="language-plaintext highlighter-rouge">$ npm install</code> successfully install all the dependencies, and voilà, but it does <strong>not</strong> work in that way, unfortunately. You still need to set up and install dependencies manually.</p>
<h3 id="1-prerequisite-install-cairo-to-the-system">1. Prerequisite: Install Cairo to the System</h3>
<p>for cat facial detection, I am using <strong>kittydar</strong>, which dependencies including <strong>node-canvas</strong>, which requires <strong>Cairo</strong>.</p>
<p>So let’s get Cairo on your Raspbian first.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++
</code></pre></div></div>
<p>See more info on how to install Cairo for Node <a href="https://github.com/Automattic/node-canvas">Canvas</a>, see this <a href="https://github.com/Automattic/node-canvas/wiki/Installation---Ubuntu-and-other-Debian-based-systems"><em>Installation Ubuntu and other Debian based systems</em></a></p>
<p>If you download the <code class="language-plaintext highlighter-rouge">node_modules</code> contents of my GitHub repo, skip the step 2, and proceed to step 3.
Otherwise, go to the next step to manually fresh-install the next several modules. Just running <code class="language-plaintext highlighter-rouge">npm install</code> to fetch all dependencies may fail because there is some incompatibilities. (I explain it later).</p>
<h3 id="2-install-dependency-modules">2. Install Dependency Modules</h3>
<p>Now, <code class="language-plaintext highlighter-rouge">cd</code> to your working directry, and install dependencies.</p>
<h4 id="install-canvas">Install Canvas</h4>
<p>You need canvas (<strong>node-canvas</strong>) to be able to analyze images with KittyDar.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>npm <span class="nb">install </span>canvas
</code></pre></div></div>
<h4 id="install-kittydar">Install KittyDar</h4>
<p><strong>Kittydar</strong> is an open-source cat face detection. It takes an image (canvas) and tells you the if cats are in the image.</p>
<p><img src="http://res.cloudinary.com/girliemac/image/upload/v1440530252/jrfqcdul46c84qlqlks9.png" alt="Jamie detected" title="Jamie detected by KittyDar" /></p>
<p><em>This is an actual photo taken by my Raspberry Pi, while Jamie was eating, and detected by KittyDar cat facial detection!</em></p>
<p>Once your environment is set up, in this RPi-KittyCam dir, install node dependency modules.</p>
<p>Ideally install from <code class="language-plaintext highlighter-rouge">npm install kittydar —save</code></p>
<p>However, node-canvas 1.0.1 (the version specified in package.json for KittyDar) failed to build with the current Node.js (v0.12.6).</p>
<p>So what I did was download the zip from github repo into <em>node_modules</em>, alter the <code class="language-plaintext highlighter-rouge">package.json</code>, where canvas: ~1.0.1 to ^1.0.1 so that the latest canvas is installed as I <code class="language-plaintext highlighter-rouge">npm install</code> from the kittydar directory.</p>
<p>Get the zip from <a href="https://github.com/girliemac/kittydar">my forked repo</a>.</p>
<p><em>Note: Although, the repo is no longer maintained by the author, I am sending <a href="https://github.com/harthur/kittydar/pull/27]">a pull request</a> for the fix.</em></p>
<h4 id="install-johnny-five">Install Johnny-Five</h4>
<p><strong>Johnny-Five</strong> is a JavaScript Robotics programming framework. It makes communicating with hardware so much easier.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>johnny-five
</code></pre></div></div>
<h4 id="install-raspi-io">Install Raspi-io</h4>
<p><strong>Raspi-io</strong> is a library to be used as an I/O plugin with Johnny-Five. You need to install this to use Johnny-Five on Raspbian.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>raspi-io
</code></pre></div></div>
<h3 id="3-install-3rd-party-service-modules">3. Install 3rd Party Service Modules</h3>
<p>This step is optional, if you don’t want to create a web interface to stream the photos, or you would rather create your own web server without depending on the 3rd party services.</p>
<h4 id="install-pubnub">Install PubNub</h4>
<p>For realtime live-updating the web interface, I am using PubNub.
To use the service, you need to <a href="http://pubnub.com">sign up</a> to obtain your API keys.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>pubnub
</code></pre></div></div>
<h4 id="install-cloudinary">Install Cloudinary</h4>
<p>For storing photos, use Cloudinary.
To use the service, you need to <a href="http://cloudinary.com/">sign up</a> to obtain your API keys.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>npm <span class="nb">install </span>cloudinary
</code></pre></div></div>
<h4 id="set-up-your-configjs-with-credentials">Set up your config.js with Credentials</h4>
<p>Create a <code class="language-plaintext highlighter-rouge">config.js</code> in the root dir of the app.
The file should include your API keys:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">cloudinary</span><span class="p">:</span> <span class="p">{</span>
<span class="na">cloud_name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">your_name</span><span class="dl">'</span><span class="p">,</span>
<span class="na">api_key</span><span class="p">:</span> <span class="dl">'</span><span class="s1">your_API_key</span><span class="dl">'</span><span class="p">,</span>
<span class="na">api_secret</span><span class="p">:</span> <span class="dl">'</span><span class="s1">your_API_secret</span><span class="dl">'</span><span class="p">,</span>
<span class="p">},</span>
<span class="na">pubnub</span><span class="p">:</span> <span class="p">{</span>
<span class="na">subscribe_key</span><span class="p">:</span> <span class="dl">'</span><span class="s1">your_sub_key</span><span class="dl">'</span><span class="p">,</span>
<span class="na">publish_key</span><span class="p">:</span> <span class="dl">'</span><span class="s1">your_pub_key</span><span class="dl">'</span>
<span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>
<h3 id="4-run-the-code">4. Run the Code</h3>
<p>Once you have configured everything and have all source files from my GitHub repo, try running kittyCam.js.</p>
<p>You must run with sudo:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>node kittyCam.js
</code></pre></div></div>
<p>The camera will take a photo when a motion is detected by the PIR sensor.
Then the <code class="language-plaintext highlighter-rouge">child_process</code> runs to detect if there is any cats in the photo.
When there are any cat, it sends the photo to Cloudinary.</p>
<p>Analyzed photos are deleted from the filesystem to clear up Pi.</p>
<h3 id="5-view-the-live-photo-update-on-web">5. View the Live Photo Update on Web</h3>
<ul>
<li>Get the web interface source code from <code class="language-plaintext highlighter-rouge">gh-pages</code> branch.</li>
<li>Run the <code class="language-plaintext highlighter-rouge">index.html</code> on browser</li>
</ul>
<p><img src="https://raw.githubusercontent.com/girliemac/RPi-KittyCam/gh-pages/images/screenshot.png" alt="Jamie detected" title="KittyCam Web" /></p>
<h2 id="walking-through-the-code">Walking Through the Code</h2>
<p>Although I am not writing a full tutorial how to write this Node app from scratch, I can explain some of the key features.</p>
<h3 id="detecting-motion-from-a-pir-sensor">Detecting Motion from a PIR Sensor</h3>
<p>I am using Johnny-Five’s <code class="language-plaintext highlighter-rouge">IR.Motion</code> object to detect the motion.</p>
<p>First, include the dependencies.</p>
<p>Then, create a new <code class="language-plaintext highlighter-rouge">motion</code> hardware instance at pin 7, and when a motion is detected, take a photo:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">raspi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">raspi-io</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">five</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">johnny-five</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">board</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">five</span><span class="p">.</span><span class="nx">Board</span><span class="p">({</span><span class="na">io</span><span class="p">:</span> <span class="k">new</span> <span class="nx">raspi</span><span class="p">()});</span>
<span class="nx">board</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">ready</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">motion</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">five</span><span class="p">.</span><span class="nx">Motion</span><span class="p">(</span><span class="dl">'</span><span class="s1">P1-7</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">motion</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">motionstart</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Run raspistill command to take a photo with the camera module </span>
<span class="c1">// then detect cats from the photo</span>
<span class="p">})</span>
<span class="p">});</span>
</code></pre></div></div>
<h3 id="execute-command-with-child-process">Execute Command with Child Process</h3>
<p>In the code snippet above, where the first comment is, run <code class="language-plaintext highlighter-rouge">raspistill</code> command using <code class="language-plaintext highlighter-rouge">child_process.spawn()</code> to take a photo with the camera module:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">filename</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">photo/image_</span><span class="dl">'</span><span class="o">+</span><span class="nx">i</span><span class="o">+</span><span class="dl">'</span><span class="s1">.jpg</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">args</span> <span class="o">=</span> <span class="p">[</span><span class="dl">'</span><span class="s1">-w</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">320</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">-h</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">240</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">-o</span><span class="dl">'</span><span class="p">,</span> <span class="nx">filename</span><span class="p">,</span> <span class="dl">'</span><span class="s1">-t</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">1</span><span class="dl">'</span><span class="p">];</span>
<span class="kd">var</span> <span class="nx">spawn</span> <span class="o">=</span> <span class="nx">child_process</span><span class="p">.</span><span class="nx">spawn</span><span class="p">(</span><span class="dl">'</span><span class="s1">raspistill</span><span class="dl">'</span><span class="p">,</span> <span class="nx">args</span><span class="p">);</span>
<span class="nx">spawn</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">exit</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">A photo is saved as </span><span class="dl">'</span><span class="o">+</span><span class="nx">filename</span><span class="o">+</span> <span class="dl">'</span><span class="s1"> with exit code, </span><span class="dl">'</span> <span class="o">+</span> <span class="nx">code</span><span class="p">);</span>
<span class="nx">i</span><span class="o">++</span><span class="p">;</span>
<span class="c1">// Detect cats from photos - see the next section</span>
<span class="p">...</span>
</code></pre></div></div>
<p>Here, I am saving photos in sequential orders.</p>
<h3 id="detect-cat-with-kittydar">Detect Cat with KittyDar</h3>
<p>To be able to keep taking photos without interruptions, as each photo is being processed, I am using another <code class="language-plaintext highlighter-rouge">child_process</code>, this time with <code class="language-plaintext highlighter-rouge">fork()</code>, an instance of spawn thats runs a new instance of the V8 engine to create multiple wrokers.</p>
<p>After the comment in the code snippet above, read another JS file:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">imgPath</span> <span class="o">=</span> <span class="nx">__dirname</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">/</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">filename</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">args</span> <span class="o">=</span> <span class="p">[</span><span class="nx">imgPath</span><span class="p">];</span>
<span class="kd">var</span> <span class="nx">fork</span> <span class="o">=</span> <span class="nx">child_process</span><span class="p">.</span><span class="nx">fork</span><span class="p">(</span><span class="nx">__dirname</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">/detectCatsFromPhoto.js</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">fork</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">args</span><span class="p">);</span>
<span class="c1">// the child process is completed</span>
<span class="nx">fork</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">message</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">base64</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="nx">base64</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// send the image to the cloud storage</span>
<span class="p">}</span>
<span class="nx">deletePhoto</span><span class="p">(</span><span class="nx">imgPath</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>
<p>In <strong>detectCatsFromPhoto.js</strong>, start the child process and use canvas and kittydar to detect cats. Once the process is done, the image is returned in Base64:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">kittydar</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">kittydar</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">Canvas</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">kittydar/node_modules/canvas</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">message</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">imgPath</span> <span class="o">=</span> <span class="nx">m</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span><span class="nx">imgPath</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">img</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Canvas</span><span class="p">.</span><span class="nx">Image</span><span class="p">;</span>
<span class="nx">img</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">data</span><span class="p">;</span>
<span class="c1">//... snip snip, some canvas setup code here...</span>
<span class="kd">var</span> <span class="nx">cats</span> <span class="o">=</span> <span class="nx">kittydar</span><span class="p">.</span><span class="nx">detectCats</span><span class="p">(</span><span class="nx">canvas</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">base64Img</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="nx">cats</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">base64Img</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">toDataURL</span><span class="p">();</span>
<span class="p">}</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">base64Img</span><span class="p">);</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To see the entire source code, please take a look at <a href="https://github.com/girliemac/RPi-KittyCam">my GitHub repo</a>!</p>
<p>Also to see how I used PubNub to stream the live photos on web browser, look at the source code on the <a href="https://github.com/girliemac/RPi-KittyCam/tree/gh-pages">gh-pages branch</a>.</p>
<h2 id="known-issues">Known Issues</h2>
<h3 id="raspistill-camera-software">Raspistill (Camera Software)</h3>
<ul>
<li>Raspistill continuously takes a bunch of photos when I set <code class="language-plaintext highlighter-rouge">t = 0</code> (and crashes Pi while so many child process is running) so I have set <code class="language-plaintext highlighter-rouge">t = 1</code>, which causes delay. It seems to take only integer. Cats are too fast to wait for a second.</li>
<li>The camera can’t capture recognizable pics after the sun is set. The room light is too dark.</li>
</ul>
<h3 id="kittydar-cat-facial-recognition">KittyDar (Cat Facial Recognition)</h3>
<ul>
<li>During his meal time, when Jamie (my cat) is eating food in his head-down position, the facial detection fails to recognize the cat face shape.</li>
<li>When my cat moves, eats from the side of the dish, or put his butt on the camera, it fails to tell me my cat was eating.</li>
</ul>
<h4 id="the-cat-photos-failed-to-be-recognized">The cat photos failed to be recognized</h4>
<p><img src="https://raw.githubusercontent.com/girliemac/RPi-KittyCam/master/photo/image_14.jpg" alt="Jamie undetected" title="Jamie undetected" />
<img src="https://raw.githubusercontent.com/girliemac/RPi-KittyCam/master/photo/image_150.jpg" alt="Jamie undetected" title="Jamie undetected" />
<img src="https://raw.githubusercontent.com/girliemac/RPi-KittyCam/master/photo/image_166.jpg" alt="Jamie undetected" title="Jamie undetected" />
<img src="https://raw.githubusercontent.com/girliemac/RPi-KittyCam/master/photo/image_311.jpg" alt="Upside-down Jamie undetected" title="Jamie undetected" /></p>
<h2 id="omg-i-demod-kittycam-on-live-tv-show">OMG, I demo’d KittyCam on Live TV Show!</h2>
<p>See my <a href="http://www.girliemac.com/blog/2015/09/14/the-screen-savers-show/">last blog post</a> about my experience being on Twit TV! You can watch the segment on the <a href="https://twit.tv/shows/new-screen-savers/episodes/19?autostart=false">recorded show</a> too.</p>
<p>OK, I hope you enjoyed my lengthy blog post!</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://www.raspberrypi.org/">Raspberry Pi</a>: Teach, Learn, and Make with Raspberry Pi</li>
<li><a href="https://github.com/nathanjohnson320/node_arm">Node ARM</a>: Install node.js on a raspberry pi in two easy steps</li>
<li><a href="http://johnny-five.io/">Johnny-Five</a>: The original JavaScript Robotics programming framework</li>
<li><a href="https://github.com/nebrius/raspi-io">Raspi-IO</a>: An IO plugin for Johnny-Five that provides support for the Raspberry Pi</li>
<li><a href="https://github.com/harthur/kittydar">KittyDar</a>: Face detection for cats in JavaScript</li>
<li><a href="https://github.com/Automattic/node-canvas">Node Canvas</a>: A Cairo backed Canvas implementation for NodeJS</li>
<li><a href="https://www.pubnub.com/">PubNub</a>: The global realtime Data Stream Network for IoT, mobile, and web applications</li>
</ul>
https://girliemac.com/blog/2015/09/14/the-screen-savers-show2015-09-14T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p><img src="/assets/images/articles/2015/09/screensavers.jpg" alt="The Screen Savers" title="I'm on TV!" /></p>
<p>OMG, I was live on <a href="https://twit.tv/shows/new-screen-savers"><strong>The New Screen Savers Show</strong> hosted by Leo Leporte</a> last Saturday!
If you have watched this show in 90s - the early 2000s, this name must give you such a nostalgic feeling. The show is actually a revival of <a href="https://en.wikipedia.org/wiki/The_Screen_Savers">The Screen Savers Show</a>!</p>
<p>Watch me interview by TechCrunch’s Sarah Lane on the recorded video on <a href="https://twit.tv/shows/new-screen-savers/episodes/19"><strong>TWiT TV</strong></a>!</p>
<p>You may know that I made to the top page of <a href="https://news.ycombinator.com/">Hacker News</a> (and a bunch of other media) years ago with <strong>HTTP Status Cats</strong> (Now with the API at <a href="http://http.cat">http.cat</a>, thanks to <a href="https://twitter.com/rogeriopvl">Rogério Vicente</a>), and recently, I made to the top page of Hacker News again with <strong>KittyCam</strong>, a Raspberry Pi camera with cat facial detection!</p>
<p>The source code and the instruction of KittyCam is available on <a href="https://github.com/girliemac/RPi-KittyCam">GitHub</a>, and I am planning to write a step-by-step tutorial sometimes soon!</p>
<p><img src="https://camo.githubusercontent.com/8daebe6dad7087fb416cd2abb768c71aea6af58a/68747470733a2f2f6c68332e676f6f676c6575736572636f6e74656e742e636f6d2f55754b6c724e51577335774663695271493871695a4b54566f6834587254426134304c44356d5561354d496e3d77313334362d683735372d6e6f" alt="KittyCam" title="KittyCam with Jamie" /></p>
<p>Jamie detected!
And Venom detected live on camera on camera at The New Screen Savers!</p>
<p><img src="/assets/images/articles/2015/09/kittycam-web.png" alt="The Screen Savers" title="I'm on TV!" /></p>
https://girliemac.com/blog/2015/05/04/hardware-hacking-for-javascript-developers2015-05-04T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p><img src="/assets/images/articles/2015/05/imblinking.jpg" alt="I'm blinking" title="I'm blinking" /></p>
<p>I totally have neglected girliemac.com. I don’t even remember when the last time I blogged for my own website, since I started <a href="http://www.pubnub.com/blog/author/tomomi/">writing technical articles and tutorials</a> for PubNub where I joined last summer.</p>
<p>Until last year, my focus was mainly on HTML5 and mobile development, however, I am shifting towards Internet of Things movement these days. It is not that I have lost interest on the web standards but I just simply starting geeking out more with hardware.</p>
<p>I’ve always loved crafty things since I was a kid, and later in my life, I taught myself how to develop web sites, but I have zero background in electrical engineering. (Well, maybe I took some physics 101 or so, but just about it!) I can crochet and code but I didn’t know how to solder or wire. Also, I don’t know how to code in C (or something that I imagined I needed to know to program hardware). I got myself an Arduino Uno a few years ago, but I haven’t even opened the box for a long time.</p>
<p>So you wonder how I, a front-end web developer, got involved on hardware hacking.</p>
<h2 id="i-can-code-in-node-controlling-tessel-with-nodejs">I Can Code in Node! Controlling Tessel with Node.js</h2>
<p>Last year, I heard about <a href="http://tessel.io">Tessel</a>. I initially thought it was an another microcontroller that I would never even bothered, but I was so wrong. I gave it a try, and within a few hours after I touched Tessel and a camera module, I was already able to make it take my selfies and tweet it!!!</p>
<p><img src="/assets/images/articles/2015/05/tessel.jpg" alt="Tessel" title="Tessel" /></p>
<p>There are two main reasons why I was able to do so easily:</p>
<p>First, Tessel runs JavaScript, and because each Tessel contains a built-in wifi chip, internet-enabled JavaScript programs can be run directly from the device. Secondly, Tessel supports easy plug-and-play modules so I don’t have to know how to wire to be able to use sensors. Each module has an open source library on npm, so it’s literally plug, npm install, and play.</p>
<p>This simple code below snaps photos with Tessel. If you code in Node.js, you can see how easy it is to take a snap with Tessel.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">tessel</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">tessel</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">camera</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">camera-vc0706</span><span class="dl">'</span><span class="p">).</span><span class="nx">use</span><span class="p">(</span><span class="nx">tessel</span><span class="p">.</span><span class="nx">port</span><span class="p">[</span><span class="dl">'</span><span class="s1">A</span><span class="dl">'</span><span class="p">]);</span>
<span class="nx">camera</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">ready</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">camera</span><span class="p">.</span><span class="nx">takePicture</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">image</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">name</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">pic-</span><span class="dl">'</span> <span class="o">+</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">.jpg</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">sendfile</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">image</span><span class="p">);</span>
<span class="nx">camera</span><span class="p">.</span><span class="nx">disable</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
</code></pre></div></div>
<h2 id="javascript-all-the-things-meet-johnny-five">JavaScript All The Things! Meet Johnny-Five</h2>
<p>While I was wondering if Tessel is only microcentroller that runs JavaScript, I met Johnny-Five.</p>
<p><a href="http://johnny-five.io/">Johnny-Five</a> is an Open Source, Firmata Protocol based, IoT and Robotics programming framework for Node.js, developed by <a href="https://twitter.com/rwaldron">Rick Waldron</a> and his team at Bocoup. (Congrats on the new web launch!)</p>
<p>What does this mean to me?</p>
<p>It means I can start playing with other microcontroller in JavaScript, even if they uses some other languages I don’t know, such as Sketch (based on C) for Arduino.</p>
<p>Johnny-Five is supported by variety of Arduino-compatible Boards, also with using IO plugins, it supports many more boards regardless of the languages and platforms! This makes my hardware-hacking adventure so much easier.</p>
<p>Thanks to the team, using Johnny-Five is super easy. To blink an LED (in this example, with Auduino Uno), all you need to do is <code class="language-plaintext highlighter-rouge">npm install johnny-five</code> then write in Node.js like this:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">five</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">johnny-five</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">board</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">five</span><span class="p">.</span><span class="nx">Board</span><span class="p">();</span>
<span class="nx">board</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">ready</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">led</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">five</span><span class="p">.</span><span class="nx">Led</span><span class="p">(</span><span class="mi">13</span><span class="p">);</span>
<span class="nx">led</span><span class="p">.</span><span class="nx">blink</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>
<h2 id="snapping-littlebits-with-johnny-five">Snapping littleBits with Johnny-Five</h2>
<p>A year ago, I bought <a href="http://www.makershed.com/products/littlebits-arduino-starter-bundle">littleBits Auduino Starter Bundle</a>, when they announced the <em>Auduino at Heart</em> module at MakerFaire.</p>
<p><img src="/assets/images/articles/2015/05/littlebits-kit.jpg" alt="littleBits" title="littleBits" />
<em>My littleBits, photo by my coworker, Eric Grossman</em></p>
<p><a href="http://littlebits.cc/">littleBits</a> is a colorful electric modules with open-source libraries. Like Tessel, assembling the circuit is easy and it doesn’t require wiring. Actually, littleBits is far more kids-friendly that you can snap together with magnets.</p>
<p>Although littleBits works with no programming, you can snap modules with Arduino and easily incorporate programming into the circuits.</p>
<p>Thanks to Anna Gerber, who gathered all information and sample code to start <a href="https://github.com/AnnaGerber/little-bits-js">programming littleBits with Johnny-Five</a>, I can program littleBits with JavaScript, too.</p>
<p>As my first easy and fun project with littleBits & Johnny-Five, I created a <a href="https://github.com/pubnub/twitter-littlebits-blinky">Blinking notification of Twitter</a>.</p>
<p>I documented and wrote an article about this project, so please check it out on my PubNub blog, <a href="http://www.pubnub.com/blog/triggering-littlebits-leds-in-realtime-with-node-js-using-johnny-five/"><strong>Triggering littleBits LEDs with Node.js Using Johnny-Five</strong></a>.</p>
<h2 id="baking-raspberry-pi-with-johnny-five">Baking Raspberry Pi with Johnny-Five</h2>
<p>My next encounter was Raspberry Pi. Luckily, I have handful of hardware-hacking coworkers, who I can bug to ask questions.</p>
<p><a href="https://www.raspberrypi.org">Raspberry Pi</a> is a fully-functional single-board computer, rather than a microcontroller, and you can run operating system like Linux and FreeBSD (and Microsoft has announced Windows 10 for Raspberry Pi 2 recently, and <a href="https://twitter.com/girlie_mac/status/595356675898351616">I just installed it to try out</a>!) from a micro SD card. Plug it into a monitor, keyboard, and a mouse, you have a full graphical user-interface of an OS of your choice (I picked <a href="http://www.raspbian.org/">Raspbian</a>).</p>
<p>As usual, I wanted to start with LED blink, which I call <em>Hello World</em> of hardware. Unlike Tessel and Arduino, RPi board does not come with an LED, so naturally, my initial challenge was to complete the circuit. Here is the challenges (I think) I conquered:</p>
<p>####First Challenge: Get Familiarize with Breadboards</p>
<p>There are conductive metal strips goes horizontally on the back of both breadboards, except, for a 400-pin breadboard has positive and negative rails (power rails) that run vertically along the sides.
Once a wire is inserted, the component will be electrically connected to anything else placed in the same row.</p>
<p><img src="/assets/images/articles/2015/05/breadboards.png" alt="Breadboards" title="Breadboards" /></p>
<p>OK, I got it.</p>
<h4 id="next-know-your-led">Next, Know Your LED</h4>
<p>LEDs are polarized and only allow current to flow in one direction. The first thing I had to learn was that anode should be connected to the power source, and the cathode should be connected to the ground.
Each LED has two legs, a long one is an anode (+), and a short one is cathode (-).</p>
<p><img src="/assets/images/articles/2015/05/led.png" alt="Circuit" title="LED" /></p>
<h4 id="ohms-law-and-resistors">Ohm’s Law and Resistors</h4>
<p>But I am not supposed to just plug wires to a power source! Because LED has controlled current, and if I sent one too much voltage, the LED would be burned out. So I need to use resistors to limit the amount of current through an LED.</p>
<p>The LED I bought on Amazon came with a data sheet, so I can just use the numbers to calculate how much resistor I need:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>R = (Vs-Vf)/I
</code></pre></div></div>
<ul>
<li>Voltage Source (Vs) from RPi is <strong>3.3V</strong>.</li>
<li>Forward LED voltage (Vf) is <strong>1.9V</strong> (According to the data sheet)</li>
<li>Current through the LED is <strong>20mA</strong> = <strong>0.02A</strong> (Also from data sheet)</li>
</ul>
<p>So, R = (3.3v - 1.9v) / 0.02 = 70Ω</p>
<p>OK, the package of LEDs I bought came with a bunch of 200Ω resistors, so let’s just use it. The intensity of the light gets lower, but it is safe to use for sure.</p>
<p>Well, I never imagined some day I became a good friend with Ohm’s Law when I studied it in high school…</p>
<p>Now I understand how to read this circuit:</p>
<p><img src="/assets/images/articles/2015/05/circuit-led.png" alt="Circuit" title="LED circuit" /></p>
<h4 id="understand-gpio-pins">Understand GPIO Pins</h4>
<p>Raspberry Pi has the GPIO (General Purpose Input Output) pins, which are a physical interface between the Pi and the outside world. Awesome, I can program the pins to interact the inputs and outputs, for instance, I can send data from sensors and/or to devices such as LEDs!</p>
<p><img src="/assets/images/articles/2015/05/gpio.jpg" alt="GPIO" title="GPIO" /></p>
<h4 id="wire-them-up">Wire Them Up!</h4>
<p>Now I put them together, build the circuit on a breadboard using wires.</p>
<p>Use some color convention to avoid confusion:</p>
<ul>
<li>Black wires for ground</li>
<li>Red wires for voltage</li>
</ul>
<p>(Or, use gray and pink if you want!)</p>
<p><img src="/assets/images/articles/2015/05/rpi-led.jpg" alt="LED" title="LED on" /></p>
<p>Initially, I tested with Raspberry Pi’s 3.3V Pin (Red wire) to see if LED lights up just fine, then, re-wire the red wire to a GPIO pin (in this example, GPIO 4, at Physical pin 7; There are two different pin number schemes!) so I could light LED programmatically.</p>
<p><img src="/assets/images/articles/2015/05/fritzing-led-400_bb.png" alt="Circuit" title="LED circuit" />
<em>I used this super awesome open-source tool, <a href="http://fritzing.org/">Fritzing</a> to draw the breadboard!</em></p>
<h2 id="blinking-a-led-with-javascript">Blinking a LED with JavaScript</h2>
<p>Finally, it is an easy part- use Johnny-Five again to program the LED.</p>
<p>To use Johnny-Five with RPi, you need the I/O plugin, <a href="https://github.com/bryan-m-hughes/raspi-io">raspi-io</a>, written by <a href="https://twitter.com/nebrius">Bryan Hughes</a>.</p>
<p>Manipulating the LED wired to a GPIO is as easy as:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">raspi</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">raspi-io</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">five</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">johnny-five</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">board</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">five</span><span class="p">.</span><span class="nx">Board</span><span class="p">({</span><span class="na">io</span><span class="p">:</span> <span class="k">new</span> <span class="nx">raspi</span><span class="p">()});</span>
<span class="nx">board</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">ready</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">led</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">five</span><span class="p">.</span><span class="nx">Led</span><span class="p">(</span><span class="dl">'</span><span class="s1">P1-7</span><span class="dl">'</span><span class="p">);</span> <span class="c1">// Pin 7 (GPIO 4)</span>
<span class="nx">led</span><span class="p">.</span><span class="nx">blink</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Ta-da!
I was just a front-end person, writing JavaScript to build web. Now I can write JavaScript to control hardware! How awesome is that?</p>
<h2 id="i-hack-hardware-so-you-can-do-too">I Hack Hardware So You Can Do Too</h2>
<p>A few wirings (or maybe more) later, I even ran an Internet of Things Workshop with Raspberry Pi for noobs at IoT Stream Conf in April.</p>
<p>With big helps from my awesome coworkers, <a href="https://twitter.com/bhavana1110">Bhavana</a>, <a href="https://twitter.com/EM_Grossman">Eric</a>, and a Raspberry Pi Evangelist <a href="https://twitter.com/MattRichardson">Matt Richardson</a>, I played as an instructional designer to create a workshop curriculum, also as an instructor at the workshop so I could share my experiences with people who wants to get their hands dirty with Raspberry Pi too.</p>
<p>If you are interested, you can take a look at the workshop material and docs on <a href="https://github.com/pubnub/workshop-raspberrypi">GitHub</a>. The workshop <a href="https://docs.google.com/presentation/d/1edIz6OUgDnmFKiACKiL6hcl7GrnW0DHFeGt8KE5dsAw/edit?usp=sharing">walk-through slides</a> are available, too.</p>
<p>Happy hardware hacking!</p>
<h3 id="learn-more">Learn More:</h3>
<ul>
<li><a href="https://tessel.io/docs/home">Tessel Docs</a> by Technical Machine</li>
<li><a href="http://johnny-five.io/">Johnny-Five</a> by Bocoup</li>
<li><a href="https://github.com/bryan-m-hughes/raspi-io">Johnny-Five IO plugin for Raspberry Pi</a> by Bryan Hughes</li>
<li><a href="https://github.com/AnnaGerber/little-bits-js">Programming littleBits with Johnny-Five</a> by Anna Gerber</li>
<li><a href="https://www.raspberrypi.org/documentation/">Raspberry Pi Documentations</a> by Raspberry Pi Foundation</li>
<li><a href="https://learn.adafruit.com/category/learn-raspberry-pi">Learn Raspberry Pi</a> by Ada Fruit</li>
</ul>
<h3 id="also-check-them-out">Also, Check them out:</h3>
<ul>
<li><a href="http://tessel.io">Tessel</a> by Technical Machine</li>
<li><a href="http://littlebits.cc/">littleBits</a> by littleBits Electronics</li>
<li><a href="http://www.arduino.cc/en/ArduinoAtHeart/HomePage">Auduino at Heart</a> by Arduino</li>
<li><a href="https://www.raspberrypi.org">Raspberry Pi</a> by Raspberry Pi Foundation</li>
</ul>
https://girliemac.com/blog/2014/09/06/pubnub2014-09-06T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p>Note: I originally wrote this article for <a href="http://www.pubnub.com/blog/multiuser-draw-html5-canvas-tutorial/">PubNub Blog</a>, but I am re-posting it with a bit more personal touches here at girliemac.com.</p>
<p>Well, first of all, I left Nokia for the second time. It has been interesting two years at Nokia Sunnyvale office. One of the best accomplishments there is becoming an open web advocate and worked with W3C while I was there.</p>
<p>Now, I joined a San Francisco startup, called <a href="http://www.pubnub.com">PubNub</a>, which provides data streaming network. This is quite a change for my career because I have been exclusively working for mobile space, and this is the first time working outside of the industory since 2005.
Playing with data is fun, and I thought using the data with <em>Internet of Things (IoT)</em> may be more fun, too. Well, I am not really hardware savvy, so I will need to learn more about it.</p>
<hr />
<p>Yep, I am still a mobile geek, and an open web advocate at heart, naturally my first project at PubNub was about HTML5 web app (that of course supports touch events!). So here’s the digest version of my article. <a href="http://www.pubnub.com/blog/multiuser-draw-html5-canvas-tutorial/">For full article, please read it on PubNub</a>!</p>
<p><img src="/assets/images/articles/2014/09/doodle-realtime.gif" alt="Screencast" title="CoDoodler Screencast" /></p>
<p>This screencast is an actual screencast that I took while some total strangers on the InterWeb were doodling. Just about the time my free version of RecordIt terminated recording, the last person started drwaing “Teh Boobs” <em>[sic] on purpose, supposedly!</em></p>
<p>OK, so this tutorial shows you how to create a very simple doodling web app that allows multiple users draw on the canvas at the same time, using PubNub realtime JavaScript API.</p>
<p>Try this <a href="http://pubnub.github.io/codoodler/">demo</a> first, and continue reading the article and view the <a href="https://github.com/pubnub/codoodler">entire source code</a> on github and the <a href="http://codepen.io/girliemac/pen/Lxiwm">simplified code</a> on Codepen to follow the basic tutorial to fork and tweak by yourself.</p>
<h2 id="creating-basic-interactive-drawing-with-canvas">Creating Basic Interactive Drawing with Canvas</h2>
<p>Let’s create a drawing canvas.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><canvas id="drawCanvas" width="800" height="600"></canvas>
</code></pre></div></div>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var canvas = document.getElementById('drawCanvas');
var ctx = canvas.getContext('2d');
</code></pre></div></div>
<p>Now, take a user input to make the canvas drawable. This is how it works-</p>
<p>Free-drawing action is initiated when a user clicked on the canvas. A line is drawn dynamically as long as the user is holding the mouse down, and ends when it is released.</p>
<p>Let’s create some functions, which should be called upon the mouse events on canvas. The events to be observed are <code class="language-plaintext highlighter-rouge">mousedown</code>, <code class="language-plaintext highlighter-rouge">mousemove</code>, and <code class="language-plaintext highlighter-rouge">mouseup</code>:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">canvas</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">mousedown</span><span class="dl">'</span><span class="p">,</span> <span class="nx">startDraw</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
<span class="nx">canvas</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">mousemove</span><span class="dl">'</span><span class="p">,</span> <span class="nx">draw</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
<span class="nx">canvas</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">mouseup</span><span class="dl">'</span><span class="p">,</span> <span class="nx">endDraw</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
</code></pre></div></div>
<p>To include touch and pointer events support for touch-screen devices, read my old article, <a href="http://girliemac.com/blog/2013/04/17/touchy-feely-with-dom-events-rethinking-cross-device-user-interaction/">Touchy-Feely with DOM Events: Rethinking Cross-Device User Interaction</a>.</p>
<p>Now, you are going to write a <em>draw</em> function, which traces the mouse path by collecting the canvas coordinates into an array, then starts drawing the path on canvas with <code class="language-plaintext highlighter-rouge">beginPath()</code> method, connect each coordinate with <code class="language-plaintext highlighter-rouge">lineTo()</code>, and <code class="language-plaintext highlighter-rouge">stroke()</code> to complete drawing the path, while a flag, <code class="language-plaintext highlighter-rouge">isActive</code> is set <code class="language-plaintext highlighter-rouge">true</code>.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// create a flag</span>
<span class="kd">var</span> <span class="nx">isActive</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="c1">// array to collect coordinates</span>
<span class="kd">var</span> <span class="nx">plots</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">function</span> <span class="nx">draw</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">isActive</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="c1">// cross-browser canvas coordinates</span>
<span class="kd">var</span> <span class="nx">x</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">offsetX</span> <span class="o">||</span> <span class="nx">e</span><span class="p">.</span><span class="nx">layerX</span> <span class="o">-</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">offsetLeft</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">y</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">offsetY</span> <span class="o">||</span> <span class="nx">e</span><span class="p">.</span><span class="nx">layerY</span> <span class="o">-</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">offsetTop</span><span class="p">;</span>
<span class="nx">plots</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span><span class="na">x</span><span class="p">:</span> <span class="nx">x</span><span class="p">,</span> <span class="na">y</span><span class="p">:</span> <span class="nx">y</span><span class="p">});</span>
<span class="nx">drawOnCanvas</span><span class="p">(</span><span class="nx">plots</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Connecting all the (x, y) coordinates and draw a line by using canvas methods.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">drawOnCanvas</span><span class="p">(</span><span class="nx">color</span><span class="p">,</span> <span class="nx">plots</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="nx">plots</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">x</span><span class="p">,</span> <span class="nx">plots</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">y</span><span class="p">);</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="nx">i</span><span class="o"><</span><span class="nx">plots</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="nx">plots</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">x</span><span class="p">,</span> <span class="nx">plots</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">y</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Write other two functions to toggle the flag. Also empty the array after each line is drawn.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">startDraw</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">isActive</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">endDraw</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">isActive</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="c1">// empty the array</span>
<span class="nx">plots</span> <span class="o">=</span> <span class="p">[];</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Yay, you just have create a very simple drawing web app! Go on to the next step to make it even more interactive.</p>
<p><img src="http://girliemac.com/assets/images/articles/2014/09/canvas-draw.png" alt="simple draw" title="simple draw" /></p>
<h2 id="making-it-collaborative-with-multiple-users">Making It Collaborative with Multiple Users</h2>
<p>Here’s the fun part- you are going to make it as a multi-user app.</p>
<p>This is where you are going to use <a href="http://www.pubnub.com">PubNub</a> APIs. You don’t need to learn anything special here as long as you’re comfortable with JavaScript. Not even WebSocket knowledge, or node.js.</p>
<p>OK, so you can make it collabolative by <em>publishing</em> and <em>subscribing</em> the drawing path to data stream. Get your <a href="https://admin.pubnub.com/">PubNub API keys</a> ready, if you don’t have one yet, <a href="http://www.pubnub.com/get-started/">sign up</a> to get your own unique keys.</p>
<p>When you are ready, include the JavaScript libraries in your HTML to begin.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><script </span><span class="na">src=</span><span class="s">"http://cdn.pubnub.com/pubnub.min.js"</span><span class="nt">></script></span>
</code></pre></div></div>
<p>Initialize the API.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">channel</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">my-draw-demo</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">pubnub</span> <span class="o">=</span> <span class="nx">PUBNUB</span><span class="p">.</span><span class="nx">init</span><span class="p">({</span>
<span class="na">publish_key</span><span class="p">:</span> <span class="dl">'</span><span class="s1">your-publish-key</span><span class="dl">'</span><span class="p">,</span>
<span class="na">subscribe_key</span><span class="p">:</span> <span class="dl">'</span><span class="s1">your-subscribe-key</span><span class="dl">'</span>
<span class="p">});</span>
</code></pre></div></div>
<h3 id="publish-and-subscribe">Publish and Subscribe</h3>
<p>In the last step, you have created an array that hold all canvas coordinates. In this step, you are going to send one user’s drawing path data to PubNub network, also receive path data from other users.</p>
<p><img src="http://girliemac.com/assets/images/articles/2014/09/publish-subscribe.png" alt="Publish and Subscribe" title="PubNub Data Stream" /></p>
<p>To send data, all you have to do is broadcast the array to the channel with one of the data stream APIs, <code class="language-plaintext highlighter-rouge">publish()</code>. Simply add these lines of code in your <code class="language-plaintext highlighter-rouge">endDraw()</code> function, just before emptying array.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">pubnub</span><span class="p">.</span><span class="nx">publish</span><span class="p">({</span>
<span class="na">channel</span><span class="p">:</span> <span class="nx">channel</span><span class="p">,</span>
<span class="na">message</span><span class="p">:</span> <span class="p">{</span>
<span class="na">plots</span><span class="p">:</span> <span class="nx">plots</span> <span class="c1">// your array goes here</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre></div></div>
<p>To retrieve the published data, you simply need <code class="language-plaintext highlighter-rouge">subscribe()</code>.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">pubnub</span><span class="p">.</span><span class="nx">subscribe</span><span class="p">({</span>
<span class="na">channel</span><span class="p">:</span> <span class="nx">channel</span><span class="p">,</span>
<span class="na">callback</span><span class="p">:</span> <span class="nx">drawFromStream</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Once you successfully retrieve the data object from the stream, call the callback function to draw lines from the received array data on canvas, just like you did in the last step.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">drawFromStream</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">message</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">drawOnCanvas</span><span class="p">(</span><span class="nx">message</span><span class="p">.</span><span class="nx">plots</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Ta-da, you just have create a very simple multi-user canvas app!</p>
<p>If you are interested in, read on the entire tutorial, at <a href="http://www.pubnub.com/blog/multiuser-draw-html5-canvas-tutorial/">PubNub Blog</a>!</p>
https://girliemac.com/blog/2014/07/28/devicemode2014-07-28T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p>Note: I originally wrote this article for <a href="http://html5experts.jp/girlie_mac/8384/">HTML5Experts.jp</a> in Japanese, as a part of their Google I/O special editions. This blog post is more of the abridged version of my original article, which uses more actual quotes (translated) from Google I/O.</p>
<hr />
<h2 id="device-mode">Device Mode</h2>
<p>Last month at Google I/O, <a href="http://paulbakaus.com">Paul Bakaus</a> introduced a set of brand-new (still experimental) tools, called <em>Device Mode</em> for Chrome DevTools. Currently, this feature is only available on Chrome Canary (v38 and newer).</p>
<p>The Device Mode comes with presets of device information including screen width, height, and device pixel ratio from popular devices, like Nexus 5 and Samsung Galaxy series, and makes responsively designed web development easy for us.</p>
<h2 id="media-queries-tool">Media-Queries Tool</h2>
<p>Once you open DevTools in Chrome Canary, you see a little device icon on left in tab bar at the top. By clicking the icon, the regular webpage display pane becomes the device mode. Here you can resize the window along the ruler UI, or choose one of the devices from a dropdown menu. If you choose a device with a large resolution, you can make the screen shrinks to fit in the display pane too. Also, switching its orientaion by swapping the width and height values by clicking the toggle icon.</p>
<p><img src="/assets/images/articles/2014/07/devtools-device-mode-1.gif" alt="devicemode01" title="Device Mode" /></p>
<p>What I found more useful in this Device Mode is the Media-queries tool. Clicking the icon at the left side of the device presets (the one looks like steps), you get the visual representations of the media-queries used for the page. Select one of these bars from the UI and right-click it gives you a select menu that says “Reveal In Source Code”, so mouseover it to view all CSS file paths. Click a file to inspect the source code!</p>
<p><img src="/assets/images/articles/2014/07/devtools-device-mode-2.gif" alt="devicemode02" title="Media-queries" /></p>
<p>Apparently, with another new feature called Workspace, you can edit the media-queries on DevTools directly, and the changes reflect to the local file systems on the fly.</p>
<h2 id="connectivity">Connectivity</h2>
<p>The new tool comes with the network emulation presets as well. From the dropdown next to the device menu, you can pick mobile networks like 3G and EDGE to emulate the connectivity, and make performance testing easier.</p>
<p><img src="/assets/images/articles/2014/07/devtools-device-mode-3.gif" alt="devicemode03" title="Network" /></p>
<h2 id="remote-debugging-with-screencast">Remote Debugging with Screencast</h2>
<p>There is a newer addition to the Device Mode- a better screencasting feature. This obscure feature has been intruduced to Chrome DevTools already a while ago, but the new and improved features just landed to Canary as an experimental tool. This new screencast comes with Canary build 38.0.2101.0 and newer.</p>
<p>To use the experimental features, you need to enable the <em>DevTools Experiments</em> from <code class="language-plaintext highlighter-rouge">chrome://flags/#enable-devtools-experiments</code>. Then open the DevTools and click the gear icon to manually turn on the screencast feature.</p>
<p>Also, you need to <a href="https://developer.chrome.com/devtools/docs/remote-debugging#setting-up-device">enable USB Debug mode</a> on your Android device.</p>
<p>Once you connect a deivice to your desktop with a USB cable, you should see an little device icon with “1”, which indicates the number of devices connected. Then click “Try Here” button to open a screencast window.</p>
<p><img src="/assets/images/articles/2014/07/devtools-device-mode-screencast.jpg" alt="screencast" title="Screencast" /></p>
<p>Typing a URL onto the DevTools reflects on your device. Your device should launch the web page on Chrome.
And you should be able to navigate the page from both device and the screencast.
Clicking “Layers” tab gives you a visualized DOM layers to measure rendering and painting. You can pinpoint where painting jankiness occurs with another new feature, Paint Profiler too!</p>
<p><img src="/assets/images/articles/2014/07/devtools-device-mode-screencast.gif" alt="screencast" title="Screencast" /></p>
<h2 id="takeaways">Takeaways</h2>
<p>Here is a list of the DevTools new features for mobile development:</p>
<p>Responsive Layouts</p>
<ul>
<li>Rich reprresentsation of media-queries</li>
<li>Style filtering</li>
<li>Media-queries editting</li>
<li>Inline emulation</li>
</ul>
<p>Rich Emulaton</p>
<ul>
<li>Device presets for most popular devices</li>
<li>Rich viewport emulation</li>
<li>Sensor emulation (touch, geolocation, accelerometer)</li>
<li>Network throttling and offline</li>
</ul>
<p>Remote Debugging</p>
<ul>
<li>Plug and play</li>
<li>Existing but more powerful features</li>
<li>Screencast</li>
<li>Port forwarding</li>
</ul>
<p>I am pretty exited with the cool new features, and hoping it to be more polished to make available for the stable Chrome release soon. Keep up the great work, Chrome team!</p>
https://girliemac.com/blog/2014/07/03/indexeddb2014-07-03T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p><img src="/assets/images/articles/2014/07/coremob-camera-idb.png" alt="screenshot" title="IndexedDB in Coremob Camera app" />
“Woo-hoo, finally!!!” (I should stop being grumpy!)</p>
<p>This was the first reaction I had when I heard the new on Twitter about Chromium started supporting blob on IndexedDB. And now I know it is official after seeing the <a href="http://updates.html5rocks.com/2014/07/Blob-support-for-IndexedDB-landed-on-Chrome-Dev">blog post on HTML5 Rocks</a> by a Chrome developer advocate, also a good friend of mine, Eiji Kitamura.</p>
<p>Why was I so excited? Because I have been waited this for 1.5 years since I started writing <strong>Coremob Camera</strong>. When I started this project, IndexedDB support was super spotty, and I felt Firefox for Android was my only friend who listened to me. (FirefoxOS wasn’t quite there yet).</p>
<h2 id="coremob-camera">Coremob Camera</h2>
<p>If you have seen me talking at conferences before, you may have heard about Coremob Camera, the open web standards project I was working on, although I failed to thoroughly document it.</p>
<p><a href="https://github.com/coremob/camera/">Coremob Camera</a> is a web project that mostly I and Tobie Langel worked on for W3C’s Core Mobile Community Group (now <a href="http://www.w3.org/Mobile/IG/">Web and Mobile Interest Group</a>) to showcase the capability of the web platform, especially on mobile devices. We were hoping to help web developers out there to learn about HTML5 use cases, as well as help improve web browsers.</p>
<h2 id="the-state-of-indexeddb">The State of IndexedDB</h2>
<p>One of the key features we focused as a real-life use case is <a href="http://www.w3.org/TR/IndexedDB/">IndexedDB</a>. The good new was that Internet Explorer 10 supported IndexedDB. The bad news was that Safari had no plan of supporting it, also IndexedDB API was pretty new and unstable at that time the project started. Actually, bad news overwhelmed the good news.</p>
<p>I talked about my agony at <strong>W3Conf</strong> (<a href="https://www.youtube.com/watch?v=3Afi-v-m_Gc">video</a>) last year, then bitterly joked about complete lack of support by Apple, and IndexedDB was not ready to use, at <strong>All Your Base Conf</strong> (<a href="https://vimeo.com/83837733">video</a>, Also the slides below).</p>
<script async="" class="speakerdeck-embed" data-id="bda5d8c019b201318b443620859eaef1" data-ratio="1.6" src="//speakerdeck.com/assets/embed.js"></script>
<p>My biggest tormenters were:</p>
<ul>
<li>No adequate browser support (missing in Safari, Android stock, Presto-Opera)</li>
<li>Vendor prefix</li>
<li>Chaotic coexistence of deprecated specs and new specs on supported browsers
<ul>
<li><code class="language-plaintext highlighter-rouge">setVersion()</code> vs. <code class="language-plaintext highlighter-rouge">onupgradeneeded</code></li>
<li><code class="language-plaintext highlighter-rouge">IDBTransaction.READ_WRITE</code> vs. <code class="language-plaintext highlighter-rouge">"readwrite"</code></li>
<li>Chrome uses string for version instead of number</li>
</ul>
</li>
<li>No blob support (Only Firefox supported)</li>
</ul>
<p>The specifications have been modified multiple times. For example with Firefox’s case, the basic iDB support started in version 4, <code class="language-plaintext highlighter-rouge">setVersion()</code> was deprecated at ver 10, and transaction mode has been switched to string from constant since 13. For mobile support (Firefox’s earliest Android support was ver 16-ish), I could just stick with the latest specs; however, Chrome came to the iDB space later with slightly older specifications.</p>
<p>Because I never knew which specifications and features were supported on what browsers, also annoying issue such as Chrome’s silent failure when trying to store blobs, I had to use a bunch of feature detections and <code class="language-plaintext highlighter-rouge">try</code> / <code class="language-plaintext highlighter-rouge">catch</code> for fail-proof for the buggy Chrome 18 and Blackberry 10 (which was less PITA than Chrome).</p>
<h3 id="chromes-fashionably-late-mobile-debut">Chrome’s Fashionably Late Mobile Debut</h3>
<p>It’s 2014 now, and this year’s Google I/O was all about Android-
It is almost unbelievable for you when I say Chrome was fashionably late to the Android party. But the truth is, Chrome was not even available until late 2012, at version 18.</p>
<p>Despite the fact that Google ships Chrome quite often (along with Beta, Dev, and Canary nightly release) for desktop, I never could have any updates for my Nexus 4, during the time of the Coremob Camera development. After I patiently waited, good news came to me finally in March 2013. It was Chrome 25! Yes, there was a big gap between 18 and 25.</p>
<p>Ever since, Google constantly releases Beta version for Android as well.</p>
<h3 id="awesome-chrome-dev-tools">Awesome Chrome Dev Tools</h3>
<p>Besides the lack of blob supports, I have been always a big fan of Chrome’s <em>DevTools</em>. As well as DOM and CSS debugging, and monitoring performance, you can inspect web storages too. Visualizing the contents in your IndexedDB is easy with Chrome.</p>
<p><img src="/assets/images/articles/2014/07/devtools.gif" alt="devtools" title="Inspect iDB on Chrome DevTools" /></p>
<h2 id="to-blob-or-not-to-blob">To Blob or Not to Blob</h2>
<p>Blob support was somehow important for me, because Coremob Camera is all about photos. In the app scenario, the user flow is as follows:</p>
<ol>
<li>Take a picture via <strong>HTML Media Capture</strong></li>
<li>Use <code class="language-plaintext highlighter-rouge">FileReader()</code> to return the picture as an object</li>
<li><code class="language-plaintext highlighter-rouge">drawImage()</code> to draw the image object in canvas</li>
<li><code class="language-plaintext highlighter-rouge">getImageData()</code> to get an ImageData object containing a copy of the pixel data, then alter the pixels</li>
<li>Store the <strong>blob</strong> locally with <strong>IndexedDB</strong></li>
<li>Upload the final photo with <strong>XHR2</strong> over <strong>CORS</strong></li>
</ol>
<p>(Whoa, I successfully gave you a bunch of HTML5 use cases in a single web app, right!?)</p>
<p>For the step 5, since only Firefox was supporting blob in IndexedDB, I had to use Base64 data URL strings for unsupported browsers. Me, grumpy grumpy.</p>
<h2 id="good-news-and-more-good-news">Good news and more good news</h2>
<p>So, I felt like it has been a long time (a long InterWeb years) since I started using IndexedDB experimentally.</p>
<p><img src="/assets/images/articles/2014/07/wwdc.png" alt="WWDC" title="Safari 8" /></p>
<p>At this year’s WWDC, Apple announced new features coming to Safari 8, including yes, IndexedDB support!</p>
<p>And I am delighted with the arrival of Chrome 37, which has blob support for IndexedDB!</p>
<p>IndexedDB is finally something.</p>
<p><img src="/assets/images/articles/2014/07/cry.png" alt="yes" title="Finally!" /></p>
<p>Note: Currently, Chrome 37 (Dev) is not available on Android yet! Until then, you can try <a href="http://coremob.github.io/camera/vanilla/index.html">Coremob Camera</a> on desktop!</p>
<h2 id="references">References</h2>
<ul>
<li>W3C <a href="http://www.w3.org/TR/IndexedDB/">Indexed Database API</a></li>
<li>Can I use <a href="http://caniuse.com/indexeddb">IndexedDB?</a>?</li>
</ul>
https://girliemac.com/blog/2014/03/21/notifications2014-03-21T00:00:00-07:00Tomomi Imurahttps://girliemac.com<p><img src="/assets/images/articles/2014/03/notifications.png" alt="screenshot" title="Web notification" /></p>
<p>Two years ago, I <a href="http://girliemac.com/blog/2012/03/29/creating-non-disruptive-notifications-with-html5/">wrote a demo and blogged</a> about then-Chrome-only HTML5 notifications. A while ago, like, 8 Chrome versions ago, I’ve noticed the demo no longer worked, because the <a href="http://www.chromium.org/developers/design-documents/desktop-notifications/api-specification">original specication</a> I was using was deprecated for good.</p>
<p>Around the time, started by Apple first, each browser vendors had its own proprietary notifications API, then last year, they have decided to standardized specification.</p>
<p>I finally read the <a href="http://www.w3.org/TR/notifications">new specifications on W3C</a> recently, and rewrote the demo using the standard API.</p>
<h2 id="new-and-simplified-specs">New and Simplified Specs</h2>
<p>In the original demo, I implemented the notifications in <em>webOS 3.0-style</em> UX, which allowed a user to swipe to close the window. (Do you remember HP TouchPad, which was killed soon after the release and gone on fire-sale? I was a UI engineer for the beautiful dead platform.) However, <a href="http://girliemac.com/html5-notifications-webOS-style/">this v2 demo</a> no longer supports the swipable notifications UI because the simplified new Web Notifications spcification only allows text and icon, and external HTML (with JS) files are no longer permitted.</p>
<h2 id="demo">Demo</h2>
<p>Check out the new demo: <a href="http://girliemac.com/html5-notifications-webOS-style/">http://girliemac.com/html5-notifications-webOS-style</a> (I keep the webOS system config look-and-feel!)</p>
<p>The simplified standard uses <code class="language-plaintext highlighter-rouge">Notification</code> object to represent each notification. (No <code class="language-plaintext highlighter-rouge">webkit</code> or <code class="language-plaintext highlighter-rouge">moz</code> vendor prefixes are required for the supported browsers.)</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">notification</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Notification</span><span class="p">(</span><span class="dl">'</span><span class="s1">YOLO!</span><span class="dl">'</span><span class="p">);</span>
</code></pre></div></div>
<h3 id="request-permission">Request Permission</h3>
<p><img src="/assets/images/articles/2014/03/permission.png" alt="screenshot" title="Web notification" /></p>
<p>Notifications can only be displayed if the user has granted permission. Requesting the user agent to ask a user for permission is done as follows:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">Notification</span><span class="p">.</span><span class="nx">requestPermission</span><span class="p">(</span><span class="nx">callback</span><span class="p">);</span>
</code></pre></div></div>
<p>This process is done asynchronously, and the callback function is called when the user chooses a permission either <code class="language-plaintext highlighter-rouge">default</code>, <code class="language-plaintext highlighter-rouge">granted</code>, or <code class="language-plaintext highlighter-rouge">denied</code>.</p>
<h3 id="displaying-notifications">Displaying Notifications</h3>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="nx">Notification</span><span class="p">.</span><span class="nx">permission</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">granted</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">n</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Notification</span><span class="p">(</span><span class="dl">'</span><span class="s1">Meeting</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
<span class="na">body</span><span class="p">:</span> <span class="dl">'</span><span class="s1">March 21 3:30 PM</span><span class="dl">'</span><span class="p">,</span>
<span class="na">icon</span><span class="p">:</span> <span class="dl">'</span><span class="s1">calendar.png</span><span class="dl">'</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p><img src="/assets/images/articles/2014/03/notification-window.png" alt="screenshot" title="Notifications on Chrome" /></p>
<h3 id="events">Events</h3>
<p><code class="language-plaintext highlighter-rouge">Notification</code> fires <code class="language-plaintext highlighter-rouge">show</code> and <code class="language-plaintext highlighter-rouge">close</code> events during the lifecycle.</p>
<p>To close the notification window after 15 seconds:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">n</span><span class="p">.</span><span class="nx">onshow</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">setTimeout</span><span class="p">(</span><span class="nx">n</span><span class="p">.</span><span class="nx">close</span><span class="p">,</span> <span class="mi">15000</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="supported-browsers">Supported Browsers</h2>
<ul>
<li>Firefox 22+ (both desktop and mobile)</li>
<li>Chrome 32+ (Desktop only)</li>
<li>Safari 6+ on Mac 10.8+ (Damnit, I need to upgrade my Mac to test!)</li>
</ul>
<p>As long as I tested, the web notifications API is disabled on Chrome for mobile, while Firefox does support the feature (however, it has a UI issue).</p>
<h2 id="known-problems">Known Problems</h2>
<ul>
<li>Chrome for Android does not support the feature</li>
<li>Firefox on Android does support, however, only one line (the last line) is displayed on the native notification bar on top. No extra UI or window from browser. (tested on Firefox 29. Bug filed #986785.)</li>
<li>On Chrome (tested on 33), <code class="language-plaintext highlighter-rouge">close()</code> method does not seem to work. Notification windows fails to close automatically. (Bug filed #355214).</li>
</ul>
<h3 id="firefox-on-android">Firefox on Android</h3>
<p>Notifications appear in the native notification bar, one at a time, instead of popup windows from browser.</p>
<p>The problem is that if a notificatin contains more than one lines one messages (when both main text and <code class="language-plaintext highlighter-rouge">body</code> are set), only the last line (<code class="language-plaintext highlighter-rouge">body</code>) is displayed, instead of the main title, which I think makes more sense. When the notification bar is expanded by a user, both subject and body text are visible (See the screenshot below).</p>
<p>Also, custom icons aren’t shown either. The icon on the notification is always Firefox icon.</p>
<p><img src="/assets/images/articles/2014/03/notifications-moz.png" alt="screenshot" title="Notifications from Firefox on Android" /></p>
<h2 id="references">References</h2>
<ul>
<li>W3C <a href="http://www.w3.org/TR/notifications">Web Notifications</a></li>
<li>WHATWG <a href="http://notifications.spec.whatwg.org/">Notifications AP</a></li>
<li>Can I use <a href="http://caniuse.com/notifications">Web Notifications</a>?</li>
<li>MDN <a href="https://developer.mozilla.org/en-US/docs/WebAPI/Using_Web_Notifications">Using Web Notifications</a></li>
<li>Apple Safari Developer Library <a href="https://developer.apple.com/library/safari/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/SendingNotifications.html">Sending Notifications</a></li>
</ul>