<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Keyang&#39;s Blog</title>
  
  <subtitle>A home of Javascript</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://keyangxiang.com/"/>
  <updated>2019-09-06T15:51:43.515Z</updated>
  <id>http://keyangxiang.com/</id>
  
  <author>
    <name>Keyang Xiang</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>hello</title>
    <link href="http://keyangxiang.com/2019/09/06/hello/"/>
    <id>http://keyangxiang.com/2019/09/06/hello/</id>
    <published>2019-09-06T15:50:55.000Z</published>
    <updated>2019-09-06T15:51:43.515Z</updated>
    
    <content type="html"><![CDATA[<script src="https://gist.github.com/Keyang/8948c0046917c289bff8b0fbcd9d05ae.js"></script>]]></content>
    
    <summary type="html">
    
      
      
        &lt;script src=&quot;https://gist.github.com/Keyang/8948c0046917c289bff8b0fbcd9d05ae.js&quot;&gt;&lt;/script&gt;
      
    
    </summary>
    
    
    
  </entry>
  
  <entry>
    <title>Run Nginx as reverse proxy on Openshift</title>
    <link href="http://keyangxiang.com/2018/06/01/Openshift/how-to-run-nginx-as-reverse-proxy/"/>
    <id>http://keyangxiang.com/2018/06/01/Openshift/how-to-run-nginx-as-reverse-proxy/</id>
    <published>2018-06-01T16:32:24.000Z</published>
    <updated>2018-06-14T10:12:55.000Z</updated>
    
    <content type="html"><![CDATA[<p>In this post, I will introduce a way to deploy a Nginx Reverse Proxy to Openshift base on <a href="https://access.redhat.com/containers/?tab=overview&platform=openshift#/registry.access.redhat.com/rhscl/nginx-112-rhel7" target="_blank" rel="noopener">RedHat certified Nginx Builder Image</a>.</p><a id="more"></a><p>In my previous post: <a href="http://keyangxiang.com/2017/10/24/Openshift/How-to-run-nginx-on-openshift-and-deploy-website/">How to deploy website to openshift with nginx</a>, I simply introduced how to use the Nginx Builder Image to deploy a website on Openshift. </p><p>Reverse Proxy configuration, however, is not part of web content. Thus it is not able to directly to use the Builder Image to setup the config and we will need create a real Nginx Image which can be futher configured with reverse proxy table.</p><p><img src="https://www.plantuml.com/plantuml/png/oyjFILLGSYhDp4b9BLBmIy_Cgr3mp4rCJrLII2nMICfKuCe3gu38E2KMfo99vu44KHG4fPQb5WKKvLTKWXKKW5WAN4cPkdPGjI1IrmuipiK50000" alt="image"></p><h1 id="Step-1-–-Create-Nginx-base-image"><a href="#Step-1-–-Create-Nginx-base-image" class="headerlink" title="Step 1 – Create Nginx base image"></a>Step 1 – Create Nginx base image</h1><p>We are creating the Nginx Base Image based on <a href="https://access.redhat.com/containers/?tab=overview&platform=openshift#/registry.access.redhat.com/rhscl/nginx-112-rhel7" target="_blank" rel="noopener">RedHat certified Nginx Builder Image</a> (rhscl/nginx-112-rhel7). </p><p>First, let’s create an app that has an empty <code>index.html</code> page from local directory (e.g. <code>$HOME/webfolder</code>):</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">oc new-app registry.access.redhat.com/rhscl/nginx-112-rhel7~<span class="variable">$HOME</span>/webfolder --name=nginxbase</span><br></pre></td></tr></table></figure><p>This will create corresponding resources like <code>buildconfig</code>, <code>deploymentconfig</code>, <code>imagestream</code>, <code>service</code> etc for <code>nginxbase</code> in Openshift.</p><p>Once resources created successfully, let’s build the image</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">oc start-build nginxbase --from-dir=<span class="variable">$HOME</span>/webfolder</span><br></pre></td></tr></table></figure><p>This will create the Nginx Base image and push to registry in Openshift.</p><p>Once the <code>nginxbase</code> image being created, we could remove all other resources:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">oc delete bc/nginxbase</span><br><span class="line">oc delete dc/nginxbase</span><br><span class="line">oc delete svc/nginxbase</span><br></pre></td></tr></table></figure><h1 id="Step-2-–-Add-reverse-proxy-configuration"><a href="#Step-2-–-Add-reverse-proxy-configuration" class="headerlink" title="Step 2 – Add reverse proxy configuration"></a>Step 2 – Add reverse proxy configuration</h1><p>We will need create a custom image for reverse proxy. First, create an empty folder and add following files:</p><ul><li>Dockerfile</li><li>nginx-proxy.conf: the proxy definition file</li></ul><p>In <code>Dockerfile</code>, add following content:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> nginxbase:latest</span><br><span class="line"><span class="keyword">ADD</span><span class="bash"> nginx-proxy.conf /opt/app-root/etc/nginx.default.d/nginx-proxy.conf</span></span><br></pre></td></tr></table></figure><p>When nginx server starts, it will automatically load configuration files <code>*.conf</code> in <code>/opt/app-root/etc/nginx.default.d</code> folder into its default server definition closure. So we add our <code>nginx-proxy</code> configuration file into that folder.</p><p>In <code>nginx-proxy.conf</code> file, we could add reverse proxy configuration. For example:</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">location</span> /userProfile &#123;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  Host <span class="variable">$host</span>;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Forwarded-Proto https;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Forwarded-For <span class="variable">$remote_addr</span>;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Forwarded-Host <span class="variable">$remote_addr</span>;</span><br><span class="line">  <span class="attribute">proxy_pass</span> http://userProfile:8080;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="attribute">location</span> /uploadAsset &#123;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  Host <span class="variable">$host</span>;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Forwarded-Proto https;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Forwarded-For <span class="variable">$remote_addr</span>;</span><br><span class="line">  <span class="attribute">proxy_set_header</span>  X-Forwarded-Host <span class="variable">$remote_addr</span>;</span><br><span class="line">  <span class="attribute">proxy_buffering</span> <span class="literal">off</span>;</span><br><span class="line">  <span class="attribute">client_max_body_size</span> <span class="number">50m</span>;</span><br><span class="line">  <span class="attribute">proxy_pass</span> http://uploadAsset:8080;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="Step-3-–-Create-Reverse-Proxy"><a href="#Step-3-–-Create-Reverse-Proxy" class="headerlink" title="Step 3 – Create Reverse Proxy"></a>Step 3 – Create Reverse Proxy</h1><p>Next, create reverse proxy app in Openshift:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">oc new-app --strategy=docker nginxbase~&lt;path to dockerfile&gt; --name=myReverseProxy</span><br></pre></td></tr></table></figure><p>Just be aware we have to use <code>docker strategy</code> as app’s build strategy so that Openshift knows that we will upload a Docker project.</p><p>Start Build:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">oc start-build myReverseProxy --from-dir=&lt;path to dockerfile&gt;</span><br></pre></td></tr></table></figure><p>Once the build finished, Openshift should automatically deploy a new pod up and running. We could expose the reverse proxy by running</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">oc expose svc/myReverseProxy</span><br></pre></td></tr></table></figure><p>and access the nginx reverse proxy through the routes created.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;In this post, I will introduce a way to deploy a Nginx Reverse Proxy to Openshift base on &lt;a href=&quot;https://access.redhat.com/containers/?tab=overview&amp;platform=openshift#/registry.access.redhat.com/rhscl/nginx-112-rhel7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RedHat certified Nginx Builder Image&lt;/a&gt;.&lt;/p&gt;
    
    </summary>
    
    
      <category term="Openshift" scheme="http://keyangxiang.com/categories/Openshift/"/>
    
    
      <category term="nginx" scheme="http://keyangxiang.com/tags/nginx/"/>
    
      <category term="openshift" scheme="http://keyangxiang.com/tags/openshift/"/>
    
  </entry>
  
  <entry>
    <title>How to Run Minishift On MacOSX</title>
    <link href="http://keyangxiang.com/2018/05/18/Openshift/how-to-run-minishift-on-macos/"/>
    <id>http://keyangxiang.com/2018/05/18/Openshift/how-to-run-minishift-on-macos/</id>
    <published>2018-05-18T17:40:23.000Z</published>
    <updated>2018-05-18T09:50:41.000Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://github.com/minishift/minishift" target="_blank" rel="noopener">Minishift</a> allows running a mini-version of Openshift cluster locally for convenience of development and debug. This blog is going through how to run minishift on MacOS.</p><a id="more"></a><h1 id="Step1-–-Download-latest-Minishift"><a href="#Step1-–-Download-latest-Minishift" class="headerlink" title="Step1 – Download latest Minishift"></a>Step1 – Download latest Minishift</h1><p>Goto <a href="https://github.com/minishift/minishift/releases" target="_blank" rel="noopener">Mnishift Github Release Page</a>, it is able to see the binary assets of Minishift for different operation systems. By writing this article, the latest versino of Minishift for MacOS is <a href="https://github.com/minishift/minishift/releases/download/v1.17.0/minishift-1.17.0-darwin-amd64.tgz" target="_blank" rel="noopener">minishift-1.17.0-darwin-amd64.tgz</a>.</p><p>Once downloaded, expand the tar file and copy the <code>minishift</code> file to <code>/usr/local/bin</code> folder</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># untar the downloaded file</span></span><br><span class="line">tar -xvf ~/Downloads/&lt;downloaded file&gt;</span><br><span class="line"></span><br><span class="line">sudo cp ~/Downloads/&lt;expanded folder&gt;/minishift /usr/<span class="built_in">local</span>/bin</span><br><span class="line"></span><br><span class="line">sudo chmod +x /usr/<span class="built_in">local</span>/bin/minishift</span><br></pre></td></tr></table></figure><h1 id="Step2-–-Install-dependencies-Virtualization-Environment"><a href="#Step2-–-Install-dependencies-Virtualization-Environment" class="headerlink" title="Step2 – Install dependencies / Virtualization Environment"></a>Step2 – Install dependencies / Virtualization Environment</h1><p>Before Minishift can run, we need setup the virualization environment which supports Openshift running under MacOS environment.</p><p>When doing this step, I assum you have <a href="https://brew.sh/" target="_blank" rel="noopener">brew</a> installed /configured correctly in your computer.</p><p>You can simply copy and paste code below and run in a terminal.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Update brew first</span></span><br><span class="line">brew update</span><br><span class="line"><span class="comment"># install docker-machine-driver-xhyve</span></span><br><span class="line">brew install docker-machine-driver-xhyve</span><br><span class="line"><span class="comment"># Set the owner User ID (SUID) for the binary </span></span><br><span class="line">sudo chmod u+s $(brew --prefix)/opt/docker-machine-driver-xhyve/bin/docker-machine-driver-xhyve</span><br></pre></td></tr></table></figure><h1 id="Step-3-–-Run-minishift"><a href="#Step-3-–-Run-minishift" class="headerlink" title="Step 3 – Run minishift"></a>Step 3 – Run minishift</h1><p>Once setup virtualization environment successfully, let’s start minishift:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">minishift start</span><br></pre></td></tr></table></figure><p>For first time running, it will download all related dependencies including images / cli binary .</p><p>After starting successfully, it is able to see the allocated IP address to the master node of the openshift cluster. In my case it is <code>192.168.64.2</code>.</p><p>Then you should be able to open <code>https://192.168.64.2:8443</code> in your browser and login with username and password both as <code>admin</code>.</p><p>To shutdown your minishift cluster simply run:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">minishift stop</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;a href=&quot;https://github.com/minishift/minishift&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Minishift&lt;/a&gt; allows running a mini-version of Openshift cluster locally for convenience of development and debug. This blog is going through how to run minishift on MacOS.&lt;/p&gt;
    
    </summary>
    
    
      <category term="Openshift" scheme="http://keyangxiang.com/categories/Openshift/"/>
    
    
      <category term="openshift" scheme="http://keyangxiang.com/tags/openshift/"/>
    
      <category term="minishift" scheme="http://keyangxiang.com/tags/minishift/"/>
    
  </entry>
  
  <entry>
    <title>How to install Node.JS locally</title>
    <link href="http://keyangxiang.com/2018/04/01/node.js/how-to-install/"/>
    <id>http://keyangxiang.com/2018/04/01/node.js/how-to-install/</id>
    <published>2018-04-01T15:30:12.000Z</published>
    <updated>2018-05-18T09:48:58.000Z</updated>
    
    <content type="html"><![CDATA[<p>Installing Node.JS locally will take no more than 5 minutes. This post will go through the steps very quickly.</p><a id="more"></a><h1 id="Download-Installer"><a href="#Download-Installer" class="headerlink" title="Download Installer"></a>Download Installer</h1><p>First, download Node.JS installer according to target operation system from <a href="https://nodejs.org/en/download/" target="_blank" rel="noopener">here</a></p><p>The installer downloaded should be executable on target operation system (e.g. <code>.msi</code> on Window and <code>.pkg</code> on MacOSX)</p><h1 id="Run-Installer"><a href="#Run-Installer" class="headerlink" title="Run Installer"></a>Run Installer</h1><p>Follow the wizard and install Node.JS to target machine.</p><h1 id="Restart-and-Test"><a href="#Restart-and-Test" class="headerlink" title="Restart and Test"></a>Restart and Test</h1><p>Once installation finished, open a <code>bash</code> or <code>cmd</code>. Installation should have both <code>node</code> and <code>npm</code> commands exposed.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ node --version</span><br><span class="line">v6.9.5</span><br><span class="line">$ npm --version</span><br><span class="line">3.10.10</span><br></pre></td></tr></table></figure><p>It is essential to have <strong>both</strong> commands running correctly.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Installing Node.JS locally will take no more than 5 minutes. This post will go through the steps very quickly.&lt;/p&gt;
    
    </summary>
    
    
      <category term="Node.JS" scheme="http://keyangxiang.com/categories/Node-JS/"/>
    
    
      <category term="nodejs" scheme="http://keyangxiang.com/tags/nodejs/"/>
    
  </entry>
  
  <entry>
    <title>What is Node.JS? Why should I care?</title>
    <link href="http://keyangxiang.com/2018/03/31/node.js/about-nodejs/"/>
    <id>http://keyangxiang.com/2018/03/31/node.js/about-nodejs/</id>
    <published>2018-03-31T11:45:31.000Z</published>
    <updated>2018-04-02T21:07:28.000Z</updated>
    
    <content type="html"><![CDATA[<p>Node.JS has been attracting attentions for years. What is Node.JS? What makes it unique? Why should developers care about it?</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;Node.JS has been attracting attentions for years. What is Node.JS? What makes it unique? Why should developers care about it?&lt;/p&gt;

      
    
    </summary>
    
    
      <category term="Node.JS" scheme="http://keyangxiang.com/categories/Node-JS/"/>
    
    
      <category term="nodejs" scheme="http://keyangxiang.com/tags/nodejs/"/>
    
  </entry>
  
  <entry>
    <title>How to deploy website to openshift with nginx?</title>
    <link href="http://keyangxiang.com/2017/10/24/Openshift/How-to-run-nginx-on-openshift-and-deploy-website/"/>
    <id>http://keyangxiang.com/2017/10/24/Openshift/How-to-run-nginx-on-openshift-and-deploy-website/</id>
    <published>2017-10-24T21:04:14.000Z</published>
    <updated>2018-05-18T09:58:33.000Z</updated>
    
    <content type="html"><![CDATA[<p>Although Openshift is able to use docker images, it has much more restrictions like no root user. Thus not all docker images can work straight on Openshift. Unfortunately, the official <code>nginx</code> docker image does not work on openshift.</p><p>In this post, I will simply go through how to run <a href="https://access.redhat.com/containers/?tab=overview&platform=openshift#/registry.access.redhat.com/rhscl/nginx-112-rhel7" target="_blank" rel="noopener">this</a> Official RedHat nginx image on Openshift and deploy a website onto it.</p><a id="more"></a><p>So, have your <a href="https://developers.openshift.com/managing-your-applications/client-tools.html" target="_blank" rel="noopener">openshift cli tool (oc)</a> ready, let’s get started.</p><h1 id="Step-1-Create-App-Deploy-website-source-code"><a href="#Step-1-Create-App-Deploy-website-source-code" class="headerlink" title="Step 1 - Create App / Deploy website source code"></a>Step 1 - Create App / Deploy website source code</h1><p>With <code>oc</code> tool, create a new app.</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#oc new-app [BuilderImage]~[Source Code Repo]</span></span><br><span class="line">oc new-app registry.access.redhat.com/rhscl/nginx-112-rhel7~https://github.com/Keyang/keyang.github.io.git --name=myapp</span><br></pre></td></tr></table></figure><p>The openshift will pull the image from the registry and register it locally as builder image which will allow building images along with source code of website. It creates <code>build config</code>. </p><p>Then it will pull source code and <code>assemble</code> it with build image to produce another image stream.</p><p>This command will also create <code>deployment config</code> and <code>service</code>.</p><h2 id="Build-Local-Source"><a href="#Build-Local-Source" class="headerlink" title="Build Local Source"></a>Build Local Source</h2><p>If you have no accessible git repo, it is able to build againt local source.</p><p>Slightly different, create a new app on current folder</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#oc new-app [BuilderImage]~[Source Code Repo]</span></span><br><span class="line">oc new-app nginx-112-rhel7~./ --name=myapp</span><br></pre></td></tr></table></figure><p>This will not actually upload the source code from current folder to Openshift but just create a build config. Thus we need to start the build with extra parameters:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">oc start-build myapp --from-dir=./</span><br></pre></td></tr></table></figure><p>with <code>--from-dir</code> param, <code>oc</code> will upload content of current directory and builder image will <code>assemble</code> the code.</p><h1 id="Step-2-Expose-Nginx-Server"><a href="#Step-2-Expose-Nginx-Server" class="headerlink" title="Step 2 - Expose Nginx Server"></a>Step 2 - Expose Nginx Server</h1><p>Once app is created and built, we could expose it through <code>router</code>.</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">oc expose svc/myapp</span><br></pre></td></tr></table></figure><p>Once it is exposed, your nginx server and your website should be accessible with the route associated.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Although Openshift is able to use docker images, it has much more restrictions like no root user. Thus not all docker images can work straight on Openshift. Unfortunately, the official &lt;code&gt;nginx&lt;/code&gt; docker image does not work on openshift.&lt;/p&gt;
&lt;p&gt;In this post, I will simply go through how to run &lt;a href=&quot;https://access.redhat.com/containers/?tab=overview&amp;platform=openshift#/registry.access.redhat.com/rhscl/nginx-112-rhel7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this&lt;/a&gt; Official RedHat nginx image on Openshift and deploy a website onto it.&lt;/p&gt;
    
    </summary>
    
    
      <category term="Openshift" scheme="http://keyangxiang.com/categories/Openshift/"/>
    
    
      <category term="nginx" scheme="http://keyangxiang.com/tags/nginx/"/>
    
      <category term="openshift" scheme="http://keyangxiang.com/tags/openshift/"/>
    
  </entry>
  
  <entry>
    <title>How to download binary content as Blob in JS with Ajax(XHR)</title>
    <link href="http://keyangxiang.com/2017/09/01/HTML5-XHR-download-binary-content-as-Blob/"/>
    <id>http://keyangxiang.com/2017/09/01/HTML5-XHR-download-binary-content-as-Blob/</id>
    <published>2017-09-01T22:32:13.000Z</published>
    <updated>2017-12-22T23:35:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>Using <code>XMLHTTPRequest</code> (ajax) transporting data between client and server has been popular for a while. Sometimes, we want our browser to retrieve binary data from server (as <code>ArrayBuffer</code> or <code>Blob</code>) such as pdf, image, and psd files. This post will go through how to achieve it with <code>XMLHTTPRequest</code> and <code>jQuery</code>.</p><a id="more"></a><h1 id="Download-Binary-using-XMLHTTPRequest"><a href="#Download-Binary-using-XMLHTTPRequest" class="headerlink" title="Download Binary using XMLHTTPRequest"></a>Download Binary using XMLHTTPRequest</h1><p>For <code>XMLHTTPRequest</code>, just simply setup the <code>responseType</code> of <code>XHR</code> instance to either <code>arraybuffer</code> or <code>blob</code>. Example:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> xhr=<span class="keyword">new</span> XMLHTTPRequest();</span><br><span class="line">xhr.open(<span class="string">"GET"</span>, url, <span class="literal">true</span>);</span><br><span class="line"><span class="comment">//Now set response type</span></span><br><span class="line">xhr.responseType = <span class="string">'arraybuffer'</span>;</span><br><span class="line">xhr.addEventListener(<span class="string">'load'</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (xhr.status === <span class="number">200</span>)&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(xhr.response) <span class="comment">// ArrayBuffer</span></span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">new</span> Blob([xhr.response])) <span class="comment">// Blob</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line">xhr.send();</span><br></pre></td></tr></table></figure><h1 id="Download-with-jQuery-Ajax"><a href="#Download-with-jQuery-Ajax" class="headerlink" title="Download with jQuery Ajax"></a>Download with jQuery Ajax</h1><p><code>$.ajax</code> does not support either <code>arraybuffer</code> or <code>blob</code> as its <code>dataType</code>. Thus we need write a <code>beforeSend</code> handler:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//setup ajax</span></span><br><span class="line">$.ajaxSetup(&#123;</span><br><span class="line">  beforeSend:<span class="function"><span class="keyword">function</span>(<span class="params">jqXHR,settings</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (settings.dataType === <span class="string">'binary'</span>)&#123;</span><br><span class="line">      settings.xhr().responseType=<span class="string">'arraybuffer'</span>;</span><br><span class="line">      settings.processData=<span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//use ajax now</span></span><br><span class="line">$.ajax(&#123;</span><br><span class="line">  url:url,</span><br><span class="line">  dataType:<span class="string">"binary"</span>,</span><br><span class="line">  success:<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(data); <span class="comment">//ArrayBuffer</span></span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">new</span> Blob([data])) <span class="comment">// Blob</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h1 id="About-ResponseType"><a href="#About-ResponseType" class="headerlink" title="About ResponseType"></a>About ResponseType</h1><p>For more information about <code>responseType</code>, take a look at <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType" target="_blank" rel="noopener">this</a>.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Using &lt;code&gt;XMLHTTPRequest&lt;/code&gt; (ajax) transporting data between client and server has been popular for a while. Sometimes, we want our browser to retrieve binary data from server (as &lt;code&gt;ArrayBuffer&lt;/code&gt; or &lt;code&gt;Blob&lt;/code&gt;) such as pdf, image, and psd files. This post will go through how to achieve it with &lt;code&gt;XMLHTTPRequest&lt;/code&gt; and &lt;code&gt;jQuery&lt;/code&gt;.&lt;/p&gt;
    
    </summary>
    
    
    
      <category term="js" scheme="http://keyangxiang.com/tags/js/"/>
    
      <category term="web" scheme="http://keyangxiang.com/tags/web/"/>
    
  </entry>
  
  <entry>
    <title>How to make website offline accessible</title>
    <link href="http://keyangxiang.com/2017/08/17/Using-service-worker-enables-web-app-offline-usage/"/>
    <id>http://keyangxiang.com/2017/08/17/Using-service-worker-enables-web-app-offline-usage/</id>
    <published>2017-08-17T21:23:54.000Z</published>
    <updated>2017-12-22T22:08:26.000Z</updated>
    
    <content type="html"><![CDATA[<p>It is incredibly easy to make a rich web application like <a href="https://studio.psdetch.com" target="_blank" rel="noopener">psdetch</a> working offline with <a href="https://developers.google.com/web/fundamentals/getting-started/primers/service-workers" target="_blank" rel="noopener">Service Worker</a>. 5 minutes are all you need!</p><a id="more"></a><h2 id="Browser-support-–-by-time-being"><a href="#Browser-support-–-by-time-being" class="headerlink" title="Browser support – by time being"></a>Browser support – by time being</h2><ul><li>Chrome</li><li>Firefox</li><li>Edge – In development</li><li>Safari – In development</li></ul><p>More browser support details can be found <a href="https://caniuse.com/#search=service%20worker" target="_blank" rel="noopener">here</a></p><h2 id="Requirement"><a href="#Requirement" class="headerlink" title="Requirement"></a>Requirement</h2><p>To make your online only web app (like <a href="https://studio.psdetch.com" target="_blank" rel="noopener">https://studio.psdetch.com</a>) working offline, your web app needs to use <code>https</code> for security request.</p><h2 id="5-mins-development"><a href="#5-mins-development" class="headerlink" title="5 mins development"></a>5 mins development</h2><p>Very simple. The steps below works on any web apps:</p><ol><li>Follow <a href="https://googlechrome.github.io/sw-toolbox/" target="_blank" rel="noopener">this guide</a> to install <code>sw-toolbox</code></li><li>Add <code>service-worker.js</code> at the root folder of your web app. Here, the location (root folder) is important.</li><li>Add following script to <code>index.html</code></li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"/path/to/sw-toolbox/companion.js"</span> <span class="attr">data-service-worker</span>=<span class="string">"service-worker.js"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><ol start="4"><li>Add content to <code>service-worker.js</code>. You can follow the tutorial <a href="https://googlechrome.github.io/sw-toolbox/usage.html#main" target="_blank" rel="noopener">here</a>. But most situation you can just use following scripts:</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">importScripts(<span class="string">"/path/to/sw-toolbox/sw-toolbox.js"</span>);</span><br><span class="line"><span class="comment">/* this will cache all files of current web app with </span></span><br><span class="line"><span class="comment"> * "fastest" strategy. </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">toolbox.router.get(<span class="string">"/(.*)"</span>,toolbox.fastest);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* Add external files here.e.g.</span></span><br><span class="line"><span class="comment">* toolbox.router.get("https://code.jquery.com/jquery-3.2.1.min.js",toolbox.fastest);</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>You can check what I have used for <a href="https://studio.psdetch.com/service-worker.js" target="_blank" rel="noopener">psdetch</a>.</p><p>And that’s it. Your whole web app can now work offline. With <code>fastest</code> strategy, response is always returned from Cache and updated immediately if possible. This dramatically increased user experience.</p><p><img src="https://drive.google.com/uc?export=download&id=0ByuKQDQ-pFtieUQ0QVNuR1RMUUE" alt="cat relax"></p>]]></content>
    
    <summary type="html">
    
      Progress web app - enable website offline access with service worker.
    
    </summary>
    
    
    
      <category term="js" scheme="http://keyangxiang.com/tags/js/"/>
    
      <category term="web" scheme="http://keyangxiang.com/tags/web/"/>
    
  </entry>
  
  <entry>
    <title>one line generate server x509 key/cert pair</title>
    <link href="http://keyangxiang.com/2017/07/13/one-line-generate-server-x509-key-cert-pair/"/>
    <id>http://keyangxiang.com/2017/07/13/one-line-generate-server-x509-key-cert-pair/</id>
    <published>2017-07-13T12:20:08.000Z</published>
    <updated>2017-07-13T12:20:40.000Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl req -nodes -new -x509 -keyout key<span class="selector-class">.pem</span> -out cert<span class="selector-class">.pem</span> -days <span class="number">365</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;figure class=&quot;highlight stylus&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span cl
      
    
    </summary>
    
    
    
  </entry>
  
  <entry>
    <title>How to setup raspberry pi zero w with MacOS X</title>
    <link href="http://keyangxiang.com/2017/06/21/setup-raspberry-pi-zero-w-with-MacOS-X/"/>
    <id>http://keyangxiang.com/2017/06/21/setup-raspberry-pi-zero-w-with-MacOS-X/</id>
    <published>2017-06-21T22:38:44.000Z</published>
    <updated>2017-10-24T23:02:59.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Step-1-Prepare-tools"><a href="#Step-1-Prepare-tools" class="headerlink" title="Step 1 Prepare tools"></a>Step 1 Prepare tools</h1><p>To setup a brand new <a href="https://www.raspberrypi.org/products/pi-zero-w/" target="_blank" rel="noopener">raspberrypi zero w</a> you need prepare following tools:</p><ul><li>A raspberrypi zero w</li><li>mini HDMI to HDMI convert</li><li>Micro SD card</li><li>USB OTG</li><li>Mouse &amp; Keyboard</li><li>An external SD card reader</li></ul><p>All coneectors can come from seller when you purchase Raspberrypi zero w.</p><a id="more"></a><h1 id="Step-2-Download-Raspbian-Image"><a href="#Step-2-Download-Raspbian-Image" class="headerlink" title="Step 2 Download Raspbian Image"></a>Step 2 Download Raspbian Image</h1><p>You can download official <a href="https://www.raspberrypi.org/downloads/raspbian/" target="_blank" rel="noopener">Raspbian OS</a> from here. If you want use <a href="https://www.raspberrypi.org/downloads/" target="_blank" rel="noopener">other operation systems</a>, it is same setup setups.</p><h1 id="Step-3-Write-Image-to-Micro-SD-card"><a href="#Step-3-Write-Image-to-Micro-SD-card" class="headerlink" title="Step 3 Write Image to Micro SD card"></a>Step 3 Write Image to Micro SD card</h1><p><strong>Be aware, writing image to micro sd card will wipe all data on it</strong></p><p>Connect micro sd card to your mac through micro sd card reader.</p><p><img src="https://drive.google.com/uc?export=download&id=0ByuKQDQ-pFtiSnZ4VW91d1lWRXc" alt="Picture"></p><p>Once you can see your sd card in <code>finder</code>, you need find out the <code>disk</code> in system.</p><p>Open a <code>terminal</code> and run <code>diskutil list</code>:  </p><p><img src="https://drive.google.com/uc?export=download&id=0ByuKQDQ-pFtiemZJXzdLZzFHM3c" alt="Picture"></p><p>Find your sd card disk by its name. On my machine, the <code>/dev/disk2</code> in red rectangle is the <code>disk</code> in system and copy <code>disk2</code> only (not <code>/dev/disk2</code>) into clipboard.</p><p>Unmount the sd card from finder but do <strong>not</strong> unplug it.</p><p><img src="https://drive.google.com/uc?export=download&id=0ByuKQDQ-pFtib0MxZUR5QUJOc3M" alt="Picture"></p><p>Now, we need flash the image downloaded to sd card. You may need unzip it if the downloaded file is zipped by double click the file in finder. Below is the command to use:</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dd <span class="attribute">bs</span>=4M <span class="attribute">if</span>=&lt;path <span class="keyword">to</span> downloaded .img file&gt;  <span class="attribute">of</span>=/dev/r&lt;disk&gt;</span><br></pre></td></tr></table></figure><p>Replace the <code>path</code> and <code>&lt;disk&gt;</code> to your own one. </p><p><img src="https://drive.google.com/uc?export=download&id=0ByuKQDQ-pFticTM3R3lna0FudzA" alt="Pic"></p><h1 id="Step-4-Plugin-and-setup"><a href="#Step-4-Plugin-and-setup" class="headerlink" title="Step 4 Plugin and setup"></a>Step 4 Plugin and setup</h1><p>Now insert the flashed micro sd card to Raspberrypi Zero W and connect everything and you are ready to go.</p><p>[Picture]</p><h1 id="General-Problems"><a href="#General-Problems" class="headerlink" title="General Problems"></a>General Problems</h1><ul><li>Resource busy: You need unmount the partitions mounted before you could use <code>dd</code> to write the disk. See above.</li><li>Permission denied: Make sure write protection on your sd card is open. Also use external SD card reader instead of Mac built-in one which could cause this issue.</li><li>Operation not permitted: Make sure your device exists in system (check /dev/diskN)</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;Step-1-Prepare-tools&quot;&gt;&lt;a href=&quot;#Step-1-Prepare-tools&quot; class=&quot;headerlink&quot; title=&quot;Step 1 Prepare tools&quot;&gt;&lt;/a&gt;Step 1 Prepare tools&lt;/h1&gt;&lt;p&gt;To setup a brand new &lt;a href=&quot;https://www.raspberrypi.org/products/pi-zero-w/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;raspberrypi zero w&lt;/a&gt; you need prepare following tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A raspberrypi zero w&lt;/li&gt;
&lt;li&gt;mini HDMI to HDMI convert&lt;/li&gt;
&lt;li&gt;Micro SD card&lt;/li&gt;
&lt;li&gt;USB OTG&lt;/li&gt;
&lt;li&gt;Mouse &amp;amp; Keyboard&lt;/li&gt;
&lt;li&gt;An external SD card reader&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All coneectors can come from seller when you purchase Raspberrypi zero w.&lt;/p&gt;
    
    </summary>
    
    
    
      <category term="raspberrypi" scheme="http://keyangxiang.com/tags/raspberrypi/"/>
    
  </entry>
  
  <entry>
    <title>how to change MacOSX screenshot location</title>
    <link href="http://keyangxiang.com/2016/12/21/how-to-change-MacOSX-screenshot-location/"/>
    <id>http://keyangxiang.com/2016/12/21/how-to-change-MacOSX-screenshot-location/</id>
    <published>2016-12-21T20:12:34.000Z</published>
    <updated>2017-12-22T22:04:01.000Z</updated>
    
    <content type="html"><![CDATA[<p>Taking screenshots with MacOSX is very useful when writting blogs or documents. The system has powerful built-in screenshot function. However, the default location to store the screenshot files is Desktop.</p><p>This blog will go through how to change the location of screenshots to another folder.</p><a id="more"></a><h1 id="Step-1-Create-a-folder"><a href="#Step-1-Create-a-folder" class="headerlink" title="Step 1 Create a folder"></a>Step 1 Create a folder</h1><p>Create a new folder anywhere using <code>finder</code> or <code>terminal</code>. Here I created <code>blog_statics</code> folder in my Google Drive folder.</p><p><img src="https://drive.google.com/uc?export=download&id=0ByuKQDQ-pFtiVkVNYWJsWEJHbWc" alt="Picture"></p><h1 id="Step-2-Change-default-location-of-screenshots"><a href="#Step-2-Change-default-location-of-screenshots" class="headerlink" title="Step 2 Change default location of screenshots"></a>Step 2 Change default location of screenshots</h1><p>Click the created folder in last step and press <code>Command+C</code> to copy the full path to clipboard.</p><p>Press <code>Command + Space</code> and type <code>terminal</code> to open <code>terminal</code></p><p>In terminal, type following command:</p><figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">defaults <span class="keyword">write</span> com.apple.screencapture <span class="keyword">location</span> <span class="title">&lt;Folder</span> Location&gt;</span><br></pre></td></tr></table></figure><p>Note the <folder location> is the location of your create folder. You could <code>Command+V</code> to paste it from clipboard</folder></p><p>It should give following result:</p><p><img src="https://drive.google.com/uc?export=download&id=0ByuKQDQ-pFtiLUF6V2Q1alo4M3M" alt="img"></p><p>Now all new screenshots should be stored in that place.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Taking screenshots with MacOSX is very useful when writting blogs or documents. The system has powerful built-in screenshot function. However, the default location to store the screenshot files is Desktop.&lt;/p&gt;
&lt;p&gt;This blog will go through how to change the location of screenshots to another folder.&lt;/p&gt;
    
    </summary>
    
    
    
      <category term="macosx trick" scheme="http://keyangxiang.com/tags/macosx-trick/"/>
    
  </entry>
  
  <entry>
    <title>webworker notes</title>
    <link href="http://keyangxiang.com/2016/11/13/webworker-notes/"/>
    <id>http://keyangxiang.com/2016/11/13/webworker-notes/</id>
    <published>2016-11-13T21:43:04.000Z</published>
    <updated>2016-11-22T17:44:46.000Z</updated>
    
    <content type="html"><![CDATA[<p>WebWorker has now been supported by majority of browsers (<a href="http://caniuse.com/#feat=webworkers" target="_blank" rel="noopener">link</a>). I have started to use WebWorkers seriously in my projects (web pages / web apps / cordova mobile apps).</p><p>Below reference pages were used while doing my study:</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" target="_blank" rel="noopener">Using webworkers</a></li><li><a href="http://stackoverflow.com/questions/28642547/phonegap-and-webworkers" target="_blank" rel="noopener">webworker and phonegap</a></li></ul>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;WebWorker has now been supported by majority of browsers (&lt;a href=&quot;http://caniuse.com/#feat=webworkers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;li
      
    
    </summary>
    
    
    
      <category term="web, javascript" scheme="http://keyangxiang.com/tags/web-javascript/"/>
    
  </entry>
  
  <entry>
    <title>openssl quick note</title>
    <link href="http://keyangxiang.com/2016/04/24/openssl-quick-note/"/>
    <id>http://keyangxiang.com/2016/04/24/openssl-quick-note/</id>
    <published>2016-04-24T11:39:16.000Z</published>
    <updated>2017-12-23T00:22:34.000Z</updated>
    
    <content type="html"><![CDATA[<p>I found <a href="http://pki-tutorial.readthedocs.org/en/latest/simple/" target="_blank" rel="noopener">this tutorial</a> is relatively simple to follow to create a simple PKI infrastructure</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;I found &lt;a href=&quot;http://pki-tutorial.readthedocs.org/en/latest/simple/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this tutorial&lt;/a&gt; is relatively si
      
    
    </summary>
    
    
    
      <category term="openssl" scheme="http://keyangxiang.com/tags/openssl/"/>
    
  </entry>
  
  <entry>
    <title>run docker in docker</title>
    <link href="http://keyangxiang.com/2016/04/07/run-docker-in-docker/"/>
    <id>http://keyangxiang.com/2016/04/07/run-docker-in-docker/</id>
    <published>2016-04-07T16:32:14.000Z</published>
    <updated>2017-12-23T00:22:41.000Z</updated>
    
    <content type="html"><![CDATA[<p>Run docker in docker</p><figure class="highlight jboss-cli"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run <span class="params">--privileged</span> -i -t -d <span class="params">--restart=unless-stopped</span> -p 2376<span class="function">:2376</span> -p 10000-11000<span class="function">:10000-11000</span> -p 10000-11000<span class="function">:10000-11000</span>/udp -v <span class="string">/mnt/opt</span>:<span class="string">/opt</span><span class="function">:rw</span> -v <span class="string">/etc/docker</span>:<span class="string">/etc/docker</span><span class="function">:ro</span> -v <span class="string">/mnt/var/lib/docker</span>:<span class="string">/var/lib/docker</span> <span class="params">--name=docker</span> docker<span class="function">:dind</span>  -H tcp:<span class="string">//0.0.0.0</span><span class="function">:2376</span> <span class="params">--storage-driver=aufs</span> <span class="params">--tlsverify</span> <span class="params">--tlscacert</span> <span class="string">/etc/docker/ca.pem</span> <span class="params">--tlscert</span> <span class="string">/etc/docker/server.pem</span> <span class="params">--tlskey</span> <span class="string">/etc/docker/server-key.pem</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;Run docker in docker&lt;/p&gt;
&lt;figure class=&quot;highlight jboss-cli&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td
      
    
    </summary>
    
    
    
      <category term="docker" scheme="http://keyangxiang.com/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>How to send UDP packet on Linux / Unix?</title>
    <link href="http://keyangxiang.com/2016/03/31/use-nc-send-udp-packet/"/>
    <id>http://keyangxiang.com/2016/03/31/use-nc-send-udp-packet/</id>
    <published>2016-03-31T16:09:54.000Z</published>
    <updated>2017-12-23T00:22:48.000Z</updated>
    
    <content type="html"><![CDATA[<p>Netcat (nc) is very powerful tool. Install <code>apt-get install netcat</code><br>Send UDP packet with netcat:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">echo</span> <span class="string">"content goes to server"</span> | nc -<span class="keyword">u</span> <span class="symbol">&lt;ip&gt;</span> <span class="symbol">&lt;port&gt;</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;Netcat (nc) is very powerful tool. Install &lt;code&gt;apt-get install netcat&lt;/code&gt;&lt;br&gt;Send UDP packet with netcat:&lt;/p&gt;
&lt;figure class=&quot;highlig
      
    
    </summary>
    
    
    
      <category term="cli" scheme="http://keyangxiang.com/tags/cli/"/>
    
      <category term="linux" scheme="http://keyangxiang.com/tags/linux/"/>
    
  </entry>
  
  <entry>
    <title>Customised select styles</title>
    <link href="http://keyangxiang.com/2016/03/31/Customised-select-styles/"/>
    <id>http://keyangxiang.com/2016/03/31/Customised-select-styles/</id>
    <published>2016-03-30T23:25:15.000Z</published>
    <updated>2017-12-23T00:22:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>e.g.</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.select-type-1</span>&#123;</span><br><span class="line">  <span class="attribute">-webkit-appearance</span>: none;</span><br><span class="line">  <span class="attribute">-moz-appearance</span>: none;</span><br><span class="line">  <span class="attribute">appearance</span>: none;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">1em</span>;</span><br><span class="line">  <span class="attribute">border</span>:<span class="number">1px</span> solid <span class="number">#ee7122</span>;</span><br><span class="line">  <span class="attribute">color</span>:white;</span><br><span class="line">  <span class="attribute">text-align</span>: center;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">0px</span>;</span><br><span class="line">  <span class="attribute">-webkit-border-radius</span>: <span class="number">0px</span>;</span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">rgba</span>(255, 255, 255, 0.12) <span class="built_in">url</span>(<span class="string">"../img/arrowdown.png"</span>) no-repeat <span class="number">90%</span> <span class="number">50%</span>;</span><br><span class="line">  <span class="attribute">background-size</span>:<span class="number">10%</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>self-explained.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;e.g.&lt;/p&gt;
&lt;figure class=&quot;highlight css&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;
      
    
    </summary>
    
    
    
      <category term="html" scheme="http://keyangxiang.com/tags/html/"/>
    
      <category term="css" scheme="http://keyangxiang.com/tags/css/"/>
    
  </entry>
  
  <entry>
    <title>Docker multi-hosting network quick note</title>
    <link href="http://keyangxiang.com/2016/03/30/Docker-multi-hosting-network-quick-note/"/>
    <id>http://keyangxiang.com/2016/03/30/Docker-multi-hosting-network-quick-note/</id>
    <published>2016-03-30T17:24:17.000Z</published>
    <updated>2017-12-23T00:22:04.000Z</updated>
    
    <content type="html"><![CDATA[<p>To create an <code>overlay</code> network on multiple hosts over swarm, following are required:</p><ul><li>a key-value store service: this is used for broadcasting hosts / swarm agents. It can be same kv store swarm used for discovery</li><li>Run docker daemon with following parameters:<ul><li>cluster-store: where the store is</li><li>cluster-advertise: what network interface to be advertised<a id="more"></a><h1 id="Setup-consul-KV-store"><a href="#Setup-consul-KV-store" class="headerlink" title="Setup consul KV store"></a>Setup consul KV store</h1><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">docker run -d <span class="string">\</span></span><br><span class="line">    -p <span class="string">"8500:8500"</span> <span class="string">\</span></span><br><span class="line">    -h <span class="string">"consul"</span> <span class="string">\</span></span><br><span class="line">    --restart=<span class="keyword">unless</span>-stopped <span class="string">\</span></span><br><span class="line">    --name=<span class="string">"kv_store"</span><span class="string">\</span></span><br><span class="line">    progrium/consul -server -bootstrap</span><br></pre></td></tr></table></figure></li></ul></li></ul><h1 id="Daemon-Options"><a href="#Daemon-Options" class="headerlink" title="Daemon Options"></a>Daemon Options</h1><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">--engine-opt</span>=<span class="string">"cluster-store=consul://$(docker-machine ip mh-keystore):8500"</span></span><br><span class="line"><span class="attr">--engine-opt</span>=<span class="string">"cluster-advertise=eth1:2376"</span></span><br></pre></td></tr></table></figure><p><strong>All</strong> swarm-agents should have these options otherwise it will be likely get this error:</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="builtin-name">Error</span> response <span class="keyword">from</span> daemon: 500 Internal<span class="built_in"> Server </span>Error: failed <span class="keyword">to</span> parse<span class="built_in"> pool </span>request <span class="keyword">for</span><span class="built_in"> address </span>space <span class="string">"GlobalDefault"</span><span class="built_in"> pool </span><span class="string">""</span> subpool <span class="string">""</span>: cannot <span class="builtin-name">find</span><span class="built_in"> address </span>space GlobalDefault (most likely the backing datastore is <span class="keyword">not</span> configured)</span><br></pre></td></tr></table></figure><h1 id="Create-overlay-network"><a href="#Create-overlay-network" class="headerlink" title="Create overlay network"></a>Create overlay network</h1><p>If using docker-compose, there is nothing need to do. As docker-compose will automatically create defaul network if:</p><ul><li>Single host: it will create a bridge</li><li>Multiple host: it will create a overlay</li></ul><p>Once docker-compose file finished, just run <code>docker-compose up -d</code> which will create network correspondingly.</p><p>otherwise simply use following command at your <code>swarm</code>:</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker<span class="built_in"> network </span>create --driver overlay <span class="attribute">--subnet</span>=10.0.9.0/24 my-net</span><br></pre></td></tr></table></figure><h1 id="Docker-compose-build-on-Swarm"><a href="#Docker-compose-build-on-Swarm" class="headerlink" title="Docker-compose build on Swarm"></a>Docker-compose build on Swarm</h1><p>There is limitation for docker-compose build as it cannot find the target node to build the image.<br>The only way currently is to build on the node and tag it rather than on swarm.</p><figure class="highlight n1ql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="keyword">build</span> -t &lt;tag name&gt; <span class="keyword">path</span>/<span class="keyword">to</span>/dockerfile</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;To create an &lt;code&gt;overlay&lt;/code&gt; network on multiple hosts over swarm, following are required:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a key-value store service: this is used for broadcasting hosts / swarm agents. It can be same kv store swarm used for discovery&lt;/li&gt;
&lt;li&gt;Run docker daemon with following parameters:&lt;ul&gt;
&lt;li&gt;cluster-store: where the store is&lt;/li&gt;
&lt;li&gt;cluster-advertise: what network interface to be advertised
    
    </summary>
    
    
    
      <category term="docker" scheme="http://keyangxiang.com/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>get client ip address in express.js</title>
    <link href="http://keyangxiang.com/2016/03/30/get-client-ip-address-in-express-js/"/>
    <id>http://keyangxiang.com/2016/03/30/get-client-ip-address-in-express-js/</id>
    <published>2016-03-30T12:47:49.000Z</published>
    <updated>2017-12-23T00:22:16.000Z</updated>
    
    <content type="html"><![CDATA[<p>According to <a href="http://stackoverflow.com/questions/8107856/how-to-determine-a-users-ip-address-in-node" target="_blank" rel="noopener">this</a>, do following to determine the client ipaddress:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ip = (req.headers[<span class="string">'x-forwarded-for'</span>] ||</span><br><span class="line">     req.connection.remoteAddress ||</span><br><span class="line">     req.socket.remoteAddress ||</span><br><span class="line">     req.connection.socket.remoteAddress).split(<span class="string">","</span>)[<span class="number">0</span>];</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;According to &lt;a href=&quot;http://stackoverflow.com/questions/8107856/how-to-determine-a-users-ip-address-in-node&quot; target=&quot;_blank&quot; rel=&quot;noopen
      
    
    </summary>
    
    
    
      <category term="node.js" scheme="http://keyangxiang.com/tags/node-js/"/>
    
      <category term="express.js" scheme="http://keyangxiang.com/tags/express-js/"/>
    
  </entry>
  
  <entry>
    <title>Quick Note for Unit Tests in Angularjs</title>
    <link href="http://keyangxiang.com/2016/03/28/Quick-Note-for-Unit-Tests-in-Angularjs/"/>
    <id>http://keyangxiang.com/2016/03/28/Quick-Note-for-Unit-Tests-in-Angularjs/</id>
    <published>2016-03-28T14:05:54.000Z</published>
    <updated>2017-12-23T00:22:37.000Z</updated>
    
    <content type="html"><![CDATA[<p>Testing with web app is always fun. Angularjs makes it even better.<br>This quick note bootstrap any angular.js projects embracing with unit tests.</p><h1 id="Tools"><a href="#Tools" class="headerlink" title="Tools"></a>Tools</h1><p>Unit testing in Angularjs is using (by default) Jasmine and Karma.</p><p>Also, angular-mocks needs to be installed. It is needed for injection and some other mock objects.</p><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bower </span><span class="keyword">install </span>--save angular-mocks</span><br></pre></td></tr></table></figure><a id="more"></a><h1 id="Npm-dependencies"><a href="#Npm-dependencies" class="headerlink" title="Npm dependencies"></a>Npm dependencies</h1><p>Following npm packages are needed and add them as devDependencies:</p><figure class="highlight 1c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"jasmine-core"</span>: <span class="string">"^2.3.4"</span>,</span><br><span class="line"><span class="string">"karma"</span>: <span class="string">"~0.12"</span>,</span><br><span class="line"><span class="string">"karma-chrome-launcher"</span>: <span class="string">"^0.1.12"</span>,</span><br><span class="line"><span class="string">"karma-firefox-launcher"</span>: <span class="string">"^0.1.6"</span>,</span><br><span class="line"><span class="string">"karma-jasmine"</span>: <span class="string">"^0.3.5"</span>,</span><br><span class="line"><span class="string">"karma-junit-reporter"</span>: <span class="string">"^0.2.2"</span>,</span><br><span class="line"><span class="string">"protractor"</span>: <span class="string">"^2.1.0"</span></span><br></pre></td></tr></table></figure><h1 id="karma-conf-js"><a href="#karma-conf-js" class="headerlink" title="karma.conf.js"></a>karma.conf.js</h1><p>Configuration for karma:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span>(<span class="params">config</span>)</span>&#123;</span><br><span class="line">  config.set(&#123;</span><br><span class="line"></span><br><span class="line">    basePath : <span class="string">'./'</span>,</span><br><span class="line"></span><br><span class="line">    files : [</span><br><span class="line">      <span class="string">'www/bower_components/angular/angular.js'</span>,</span><br><span class="line">      <span class="string">'www/bower_components/angular-ui-router/release/angular-ui-router.js'</span>,</span><br><span class="line">      <span class="string">'www/bower_components/angular-mocks/angular-mocks.js'</span>,</span><br><span class="line">      <span class="string">'www/bower_components/jquery/dist/jquery.js'</span>,</span><br><span class="line">      <span class="comment">//all other lib dependencies</span></span><br><span class="line">      <span class="string">'www/app.gen.js'</span>, <span class="comment">// app js file &lt;- generated by browserfi</span></span><br><span class="line">      <span class="string">'www/app/**/test_*.js'</span> <span class="comment">// all tests file</span></span><br><span class="line">    ],</span><br><span class="line"></span><br><span class="line">    autoWatch : <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line">    frameworks: [<span class="string">'jasmine'</span>],</span><br><span class="line"></span><br><span class="line">    browsers : [<span class="string">'Chrome'</span>],</span><br><span class="line"></span><br><span class="line">    plugins : [</span><br><span class="line">            <span class="string">'karma-chrome-launcher'</span>,</span><br><span class="line">            <span class="string">'karma-firefox-launcher'</span>,</span><br><span class="line">            <span class="string">'karma-jasmine'</span>,</span><br><span class="line">            <span class="string">'karma-junit-reporter'</span></span><br><span class="line">            ],</span><br><span class="line"></span><br><span class="line">    junitReporter : &#123;</span><br><span class="line">      outputFile: <span class="string">'test_out/unit.xml'</span>,</span><br><span class="line">      suite: <span class="string">'unit'</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Put this file at root of project.</p><h1 id="Run-test"><a href="#Run-test" class="headerlink" title="Run test"></a>Run test</h1><ol><li>install karma-cli: <code>npm i -g karma-cli</code></li><li>run <code>karma start karma.conf.js</code></li></ol><p>This will watch all files and re-run tests if any file changes. Strongly recommended having this opened when developing.</p><h1 id="Unit-tests-for-angular-js"><a href="#Unit-tests-for-angular-js" class="headerlink" title="Unit tests for angular.js"></a>Unit tests for angular.js</h1><p>Once above setup are done, it is ready to write unit tests.</p><h2 id="Simple-example"><a href="#Simple-example" class="headerlink" title="Simple example"></a>Simple example</h2><p>Add <code>test_user.js</code> to <code>www/app/user/</code> folder or similar. Just keep <code>test_</code> file name prefix.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">describe(<span class="string">"user module"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  beforeEach(<span class="built_in">module</span>(<span class="string">'user'</span>));</span><br><span class="line">  describe(<span class="string">"auth factory"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    it (<span class="string">"should manage user session"</span>,inject(<span class="function"><span class="keyword">function</span>(<span class="params">auth</span>)</span>&#123;</span><br><span class="line">      auth.initUserWithToken(<span class="string">"abc"</span>);</span><br><span class="line">      expect(auth.getToken().token).toEqual(<span class="string">"abc"</span>);</span><br><span class="line">      auth.setPin(<span class="string">"1234"</span>);</span><br><span class="line">      expect(auth.getToken().pin).toEqual(<span class="string">"1234"</span>);</span><br><span class="line">      expect(auth.validatePin(<span class="string">"1234"</span>)).toBe(<span class="literal">true</span>);</span><br><span class="line">      expect(auth.validatePin(<span class="string">"2234"</span>)).toBe(<span class="literal">false</span>);</span><br><span class="line">      auth.logout();</span><br><span class="line">      expect(auth.validatePin(<span class="string">"1234"</span>)).toBe(<span class="literal">false</span>);</span><br><span class="line">      expect(auth.getToken()).toBe(<span class="literal">null</span>);</span><br><span class="line">    &#125;));</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Above, it first injects user module and then runs simple tests.</p><h2 id="Override-providers-factory-service"><a href="#Override-providers-factory-service" class="headerlink" title="Override providers (factory / service)"></a>Override providers (factory / service)</h2><p>If component depends on other providers, it’s able to use <code>jasmine.createSpy</code> to create dummy function.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">describe(<span class="string">"account module"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  beforeEach(<span class="built_in">module</span>(<span class="string">'account'</span>,<span class="function"><span class="keyword">function</span>(<span class="params">$provide</span>)</span>&#123;</span><br><span class="line">    $provide.value(<span class="string">'server'</span>, &#123;</span><br><span class="line">      call: jasmine.createSpy(<span class="string">'call'</span>),</span><br><span class="line">      setHeader:jasmine.createSpy(<span class="string">'setHeader'</span>)</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;));</span><br><span class="line">  describe(<span class="string">"account factory"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    it (<span class="string">"should manage accounts"</span>,inject(<span class="function"><span class="keyword">function</span>(<span class="params">account,server</span>)</span>&#123;</span><br><span class="line">      account.save();</span><br><span class="line">      expect(server.call).toHaveBeenCalled();  </span><br><span class="line">    &#125;));</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="Use-httpBackend-for-http-calls"><a href="#Use-httpBackend-for-http-calls" class="headerlink" title="Use $httpBackend for $http calls"></a>Use $httpBackend for $http calls</h2><p>Example:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">describe(<span class="string">"downStreamStore"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">var</span> ds,s,ht;</span><br><span class="line">  beforeEach(<span class="built_in">module</span>(<span class="string">"dataSync"</span>))</span><br><span class="line">  beforeEach(inject(<span class="function"><span class="keyword">function</span>(<span class="params">downStreamStore,server,$httpBackend</span>)</span>&#123;</span><br><span class="line">      ds=downStreamStore;</span><br><span class="line">      s=server;</span><br><span class="line">      ht=$httpBackend;</span><br><span class="line">  &#125;))</span><br><span class="line">  afterEach(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">       ht.verifyNoOutstandingExpectation();</span><br><span class="line">       ht.verifyNoOutstandingRequest();</span><br><span class="line">     &#125;);</span><br><span class="line">  it (<span class="string">"should retrieve data"</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    ht.when(<span class="string">"GET"</span>,<span class="string">"/test"</span>).respond(&#123;<span class="string">"hello"</span>:<span class="string">"test"</span>&#125;)</span><br><span class="line">    ht.expectGET(<span class="string">"/test"</span>);</span><br><span class="line">    ds.syncData(<span class="string">"test"</span>,<span class="string">"/test"</span>)</span><br><span class="line">    .then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">      expect(ds.get(<span class="string">"test"</span>).hello).toBe(<span class="string">"test"</span>);</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>&#123;</span><br><span class="line">      expect(e).toBeUndefined();</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    ht.flush();</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>the test above is synchrounous but with promises. Therefore no need use Jasmine async with <code>done</code>;</p><h1 id="Quick-Reference"><a href="#Quick-Reference" class="headerlink" title="Quick Reference:"></a>Quick Reference:</h1><ul><li><a href="http://jasmine.github.io/2.0/introduction.html" target="_blank" rel="noopener">Jamine</a></li><li><a href="http://karma-runner.github.io/0.13/config/configuration-file.html" target="_blank" rel="noopener">Karma Config</a></li><li><a href="https://docs.angularjs.org/guide/unit-testing" target="_blank" rel="noopener">Angular Unit Testing</a></li><li><a href="https://github.com/angular/angular-seed" target="_blank" rel="noopener">Angular Seed (Example of Unit Testing)</a></li><li><a href="https://docs.angularjs.org/api/ngMock/service/$httpBackend" target="_blank" rel="noopener">Angular $httpBackend</a></li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Testing with web app is always fun. Angularjs makes it even better.&lt;br&gt;This quick note bootstrap any angular.js projects embracing with unit tests.&lt;/p&gt;
&lt;h1 id=&quot;Tools&quot;&gt;&lt;a href=&quot;#Tools&quot; class=&quot;headerlink&quot; title=&quot;Tools&quot;&gt;&lt;/a&gt;Tools&lt;/h1&gt;&lt;p&gt;Unit testing in Angularjs is using (by default) Jasmine and Karma.&lt;/p&gt;
&lt;p&gt;Also, angular-mocks needs to be installed. It is needed for injection and some other mock objects.&lt;/p&gt;
&lt;figure class=&quot;highlight mipsasm&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;bower &lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;install &lt;/span&gt;--save angular-mocks&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
    
      <category term="angularjs" scheme="http://keyangxiang.com/tags/angularjs/"/>
    
      <category term="test" scheme="http://keyangxiang.com/tags/test/"/>
    
  </entry>
  
  <entry>
    <title>Using setter in Mongoose</title>
    <link href="http://keyangxiang.com/2016/03/20/mongoosejs-setters-schema/"/>
    <id>http://keyangxiang.com/2016/03/20/mongoosejs-setters-schema/</id>
    <published>2016-03-20T18:16:31.000Z</published>
    <updated>2017-12-23T00:22:30.000Z</updated>
    
    <content type="html"><![CDATA[<p>According to mongoose.js doc, it is able to set setters to a field on schema.<br>However, the <a href="http://mongoosejs.com/docs/2.7.x/docs/getters-setters.html" target="_blank" rel="noopener">doc</a> is not quite detailed and obselete.<br>Some example:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> schema=<span class="keyword">new</span> Schema(&#123;</span><br><span class="line">  password:&#123;</span><br><span class="line">    type:<span class="built_in">String</span>,</span><br><span class="line">    required:<span class="literal">true</span>,</span><br><span class="line">    <span class="keyword">set</span>:hash</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">function hash(plainPwd)&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">require</span>(<span class="string">"crypto"</span>).createHash(<span class="string">"sha1"</span>).update(plainPwd).update(secret).digest(<span class="string">"hex"</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><a id="more"></a><p>The <code>hash</code> will be called mainly on following scenarios:</p><ul><li><p>When a new doc being created.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">model.create(&#123;<span class="attr">password</span>:<span class="string">"12345"</span>&#125;) <span class="comment">//password will be hashed</span></span><br></pre></td></tr></table></figure></li><li><p>When set a value to a doc.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">doc.password=<span class="string">"22222"</span> <span class="comment">// 22222 will be hashed</span></span><br></pre></td></tr></table></figure></li></ul><p>However, this will not work for <code>update</code> query:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">model.update(&#123;<span class="attr">_id</span>:<span class="xml"><span class="tag">&lt;<span class="name">id</span>&gt;</span>&#125;,&#123;$set:&#123;password:"12345"&#125;&#125;) // password will not be hashed</span></span><br><span class="line"><span class="xml">model.findOneAndUpdate</span></span><br><span class="line"><span class="xml">model.findAndUpdate</span></span><br></pre></td></tr></table></figure><p>For password, it is able to write beforeUpdateHook</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">schema.methods.beforeUpdateHook=<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (!data || <span class="keyword">this</span>.password === data.password)&#123;</span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (data.password)&#123;</span><br><span class="line">    data.password=hash(data.password);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;According to mongoose.js doc, it is able to set setters to a field on schema.&lt;br&gt;However, the &lt;a href=&quot;http://mongoosejs.com/docs/2.7.x/docs/getters-setters.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;doc&lt;/a&gt; is not quite detailed and obselete.&lt;br&gt;Some example:&lt;/p&gt;
&lt;figure class=&quot;highlight js&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;11&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; schema=&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Schema(&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  password:&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    type:&lt;span class=&quot;built_in&quot;&gt;String&lt;/span&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    required:&lt;span class=&quot;literal&quot;&gt;true&lt;/span&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;    &lt;span class=&quot;keyword&quot;&gt;set&lt;/span&gt;:hash&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &amp;#125;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;function hash(plainPwd)&amp;#123;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;built_in&quot;&gt;require&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;&quot;crypto&quot;&lt;/span&gt;).createHash(&lt;span class=&quot;string&quot;&gt;&quot;sha1&quot;&lt;/span&gt;).update(plainPwd).update(secret).digest(&lt;span class=&quot;string&quot;&gt;&quot;hex&quot;&lt;/span&gt;);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
    
    </summary>
    
    
    
      <category term="node.js" scheme="http://keyangxiang.com/tags/node-js/"/>
    
      <category term="mongoose.js" scheme="http://keyangxiang.com/tags/mongoose-js/"/>
    
  </entry>
  
</feed>
