<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Random Musings</title><link>https://chengl.com/post/</link><description>Recent content in Posts on Random Musings</description><generator>Hugo</generator><language>en-us</language><copyright>Cheng Long</copyright><lastBuildDate>Sun, 05 Jul 2020 05:49:02 +0000</lastBuildDate><atom:link href="https://chengl.com/post/index.xml" rel="self" type="application/rss+xml"/><item><title>Let's Encrypt Intranet</title><link>https://chengl.com/post/lets-encrypt-intranet/</link><pubDate>Sun, 03 Sep 2017 14:33:24 +0000</pubDate><guid>https://chengl.com/post/lets-encrypt-intranet/</guid><description>&lt;p&gt;&lt;a href="https://letsencrypt.org/"&gt;Let&amp;rsquo;s Encrypt&lt;/a&gt; (LE) has been a popular choice to get certs for public websites. Because it&amp;rsquo;s free and automated. But how to get certs for &lt;strong&gt;private&lt;/strong&gt; websites, which are common in company&amp;rsquo;s intranet?&lt;/p&gt;
&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;There&amp;rsquo;s a web app in your company&amp;rsquo;s intranet.&lt;/li&gt;
&lt;li&gt;The web app has a fully qualified domain name (FQDN), e.g. &lt;strong&gt;foo.example.com&lt;/strong&gt;, not an internal one like &lt;strong&gt;foo.internal&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;It only resolves to a private IP behind VPN. Therefore, it&amp;rsquo;s inaccessible without a valid VPN.&lt;/li&gt;
&lt;li&gt;You want to add an extra layer of security by enabling HTTPS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How to get a cert for it? And how to automate it and get it for free?&lt;/p&gt;</description></item><item><title>Multirepo vs Monorepo</title><link>https://chengl.com/post/multirepo-vs-monorepo/</link><pubDate>Thu, 20 Jul 2017 09:32:00 +0000</pubDate><guid>https://chengl.com/post/multirepo-vs-monorepo/</guid><description>&lt;p&gt;Here&amp;rsquo;s a conversion I keep hearing recently:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A: Let&amp;rsquo;s put all our projects in one repo.&lt;/p&gt;
&lt;p&gt;B: Why?&lt;/p&gt;
&lt;p&gt;A: Because Google and Facebook do monorepo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Whenever I hear this, I&amp;rsquo;m very tempted to show this picture.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://chengl.com/content/images/2017/07/JohnFrumCrossTanna1967-1.jpg" alt="JohnFrumCrossTanna1967-1"&gt;&lt;/p&gt;
&lt;p&gt;Finding the origin of this picture is left as an exercise for the readers. On a more serious note, I want to write down my thoughts on multirepo vs monorepo.&lt;/p&gt;
&lt;h2 id="what-is-multirepo"&gt;What is multirepo?&lt;/h2&gt;
&lt;p&gt;One project one repository. Each project is an independent working unit. It can be a mobile app, frontend app, backend service or standalone CLI app.&lt;/p&gt;</description></item><item><title>Be wary of http/client.go</title><link>https://chengl.com/post/be-wary-of-go-http-client/</link><pubDate>Sat, 25 Mar 2017 09:30:00 +0000</pubDate><guid>https://chengl.com/post/be-wary-of-go-http-client/</guid><description>&lt;p&gt;Recently, I found out an interesting problem in Go. The problem can be reduced to a simple client request to a HTTP server.&lt;/p&gt;
&lt;p&gt;Suppose we have a HTTP server, which serves only one rooted path &lt;code&gt;/foo/&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&amp;quot;io&amp;quot;
	&amp;quot;log&amp;quot;
	&amp;quot;net/http&amp;quot;
	&amp;quot;net/http/httputil&amp;quot;
)

func handleFoo(w http.ResponseWriter, req *http.Request) {
	// request details
	dump, _ := httputil.DumpRequest(req, true)
	log.Println(string(dump))

	if auth := req.Header.Get(&amp;quot;Authorization&amp;quot;); auth != &amp;quot;Bearer GoodToken&amp;quot; {
		http.Error(w, &amp;quot;401 Unauthorized&amp;quot;, http.StatusUnauthorized)
		return
	}

	io.WriteString(w, &amp;quot;Hello World!&amp;quot;)
}

func main() {
	http.HandleFunc(&amp;quot;/foo/&amp;quot;, handleFoo)
	log.Fatal(http.ListenAndServe(&amp;quot;:12345&amp;quot;, nil))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;handleFoo&lt;/code&gt; simplily verifies that correct token is sent in the &lt;code&gt;Authorization&lt;/code&gt; header. Otherwise, it returns &lt;code&gt;401 Unauthorized&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Keeping configurations sane for multiple projects on Google Container Engine</title><link>https://chengl.com/post/working-with-multiple-projects-on-gke/</link><pubDate>Sat, 18 Feb 2017 09:27:00 +0000</pubDate><guid>https://chengl.com/post/working-with-multiple-projects-on-gke/</guid><description>&lt;p&gt;In my &lt;a href="https://chengl.com/kubectl-authentication-made-simple/"&gt;previous post&lt;/a&gt;, I present the easist and most secure way to get &lt;code&gt;kubectl&lt;/code&gt; working for one project. But what about mutiple projects? Juggle mutiple projects on Google Container Engine (GKE) can be hard, especially when its configurations are admittedly &lt;a href="https://github.com/kubernetes/kubernetes/issues/20605"&gt;quirky&lt;/a&gt;. This post describes the best practice, in my opinion, to keep configurations sane and easy to switch.&lt;/p&gt;
&lt;h2 id="problem"&gt;Problem&lt;/h2&gt;
&lt;p&gt;Suppose you have an awesome app that runs on GKE. You probably want to have two different environments &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt;, and the environments should be completely isolated. So you create two projects on GKE, &lt;code&gt;awesome-app-staging&lt;/code&gt; and &lt;code&gt;awesome-app-production&lt;/code&gt;, and provisioned resources for each. Now the question is how to effectively switch between the two projects on command line without repeating &lt;a href="https://github.com/kubernetes/kubernetes/issues/20605#issuecomment-218322105"&gt;these commands&lt;/a&gt; over and over again.&lt;/p&gt;</description></item><item><title>kubectl Authentication Made Simple</title><link>https://chengl.com/post/kubectl-authentication-made-simple/</link><pubDate>Mon, 30 Jan 2017 09:25:00 +0000</pubDate><guid>https://chengl.com/post/kubectl-authentication-made-simple/</guid><description>&lt;p&gt;While working on a continuous delivery pipeline to automate deployment to Google Container Engine (GKE), I found that getting &lt;code&gt;kubectl&lt;/code&gt; to work is very &lt;a href="https://kubernetes.io/docs/user-guide/sharing-clusters/#manually-generating-kubeconfig"&gt;complex&lt;/a&gt;&lt;a href="http://stackoverflow.com/questions/40426071/kubectl-access-to-google-cloud-container-engins-fails"&gt;and&lt;/a&gt;&lt;a href="http://stackoverflow.com/questions/40408321/whats-the-cli-authentication-process-as-of-google-container-engine-kubernetes-1"&gt;convoluted&lt;/a&gt;, especially when it needs to be &lt;a href="https://circleci.com/docs/continuous-deployment-with-google-container-engine/"&gt;noninteractive&lt;/a&gt;. So I want to find out the easiest way to get &lt;code&gt;kubectl&lt;/code&gt; working noninteractively.&lt;/p&gt;
&lt;p&gt;Assuming that &lt;code&gt;gcloud&lt;/code&gt; and &lt;code&gt;kubectl&lt;/code&gt; are already installed but not necessarily setup, &lt;strong&gt;ONLY&lt;/strong&gt; two commands are needed to get &lt;code&gt;kubectl&lt;/code&gt; working noninteractively (verified with Google Cloud SDK 141.0.0 and kubectl 1.5.2)&lt;/p&gt;</description></item><item><title>Speed Up SSH</title><link>https://chengl.com/post/speed-up-ssh/</link><pubDate>Sun, 04 Dec 2016 09:23:00 +0000</pubDate><guid>https://chengl.com/post/speed-up-ssh/</guid><description>&lt;p&gt;Recently I worked on a project where executing remote commands is very slow to start. This is expected because an SSH connection has to be established first.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ time ssh server exit
ssh server exit 0.04s user 0.01s system 0% cpu 7.901 total
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It took nearly &lt;strong&gt;8&lt;/strong&gt; seconds to ssh into &lt;code&gt;server&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s slow!&lt;/p&gt;
&lt;p&gt;After a bit of googling, there is an elegant way to speed this up. Simply put this at the bottom of your &lt;code&gt;~/.ssh/config&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Ruby and Java Stack Level</title><link>https://chengl.com/post/ruby-and-java-stack-level/</link><pubDate>Sat, 05 Nov 2016 09:17:00 +0000</pubDate><guid>https://chengl.com/post/ruby-and-java-stack-level/</guid><description>&lt;p&gt;While coding for an algorithmic problem, I discovered that Ruby&amp;rsquo;s stack level is much shallower than Java. This caused a recursive DFS solution written in Ruby failed due to &lt;code&gt;stack level too deep (SystemStackError)&lt;/code&gt;, while the same code written in Java passed. Whether recursion or tail recursion should be used is not the point of this post. This post is to find out what the max stack level is and what limits the stack level.&lt;/p&gt;</description></item><item><title>Docker Workflow</title><link>https://chengl.com/post/docker-workflow/</link><pubDate>Wed, 25 May 2016 09:07:00 +0000</pubDate><guid>https://chengl.com/post/docker-workflow/</guid><description>&lt;p&gt;In my previous posts, I demoed how to orchestrate Docker with &lt;a href="https://chengl.com/orchestrating-docker-using-swarm/"&gt;Swarm&lt;/a&gt; and &lt;a href="https://chengl.com/orchestrating-docker-with-kubernetes/"&gt;Kubernetes&lt;/a&gt;. They all assume the Docker image &lt;a href="https://hub.docker.com/r/chenglong/simple-node/"&gt;chenglong/simple-node&lt;/a&gt; is already there and ready to be deployed. But how to develop that image in the first place? How to streamline and automate the process of developing it on local machine, building and testing it on Continuous Integration (CI) server, and finally deploying to production?&lt;/p&gt;
&lt;p&gt;This post introduces one possible Docker workflow.&lt;/p&gt;</description></item><item><title>Orchestrating Docker with Kubernetes</title><link>https://chengl.com/post/orchestrating-docker-with-kubernetes/</link><pubDate>Sun, 15 May 2016 09:04:00 +0000</pubDate><guid>https://chengl.com/post/orchestrating-docker-with-kubernetes/</guid><description>&lt;p&gt;This is my second post on Docker orchestration. In &lt;a href="https://chengl.com/orchestrating-docker-using-swarm/"&gt;the first post&lt;/a&gt;, I demonstrated orchestrating Docker with Swarm, Machine, Compose and Consul. This post is to demonstrate orchestrating the same app with Kubernetes and draw comparisons between them. I recommend reading &lt;a href="https://chengl.com/orchestrating-docker-using-swarm/"&gt;that post&lt;/a&gt; before this.&lt;/p&gt;
&lt;h3 id="introduction-to-kubernetes"&gt;Introduction to Kubernetes&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Kubernetes is an open-source system for automating deployment, operations, and scaling of containerized applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It groups containers that make up an application into logical units for easy management and discovery. Kubernetes builds upon &lt;a href="http://queue.acm.org/detail.cfm?id=2898444"&gt;a decade and a half of experience of running production workloads at Google&lt;/a&gt;, combined with best-of-breed ideas and practices from the community.&lt;/p&gt;</description></item><item><title>Orchestrating Docker with Swarm, Machine, Compose and Consul</title><link>https://chengl.com/post/orchestrating-docker-using-swarm/</link><pubDate>Fri, 15 Apr 2016 09:01:00 +0000</pubDate><guid>https://chengl.com/post/orchestrating-docker-using-swarm/</guid><description>&lt;p&gt;With &lt;a href="https://blog.docker.com/2015/11/docker-multi-host-networking-ga/"&gt;multi-host networking ready for production&lt;/a&gt; and &lt;a href="https://blog.docker.com/2015/11/swarm-1-0/"&gt;the announcement of Swarm 1.0&lt;/a&gt;, I think it&amp;rsquo;s time to give Docker a serious try. This post details the steps I took to orchestrate a multi-host and multi-container app.&lt;/p&gt;
&lt;h3 id="architecture"&gt;Architecture&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://chengl.com/content/images/2017/07/Screen-Shot-2016-04-15-at-12-57-55-AM.png" alt="Screen-Shot-2016-04-15-at-12-57-55-AM"&gt;&lt;/p&gt;
&lt;p&gt;This is a simple Node app that uses Redis as database, load balanced by Nginx. Each blue box is a Docker host, which runs several containers. All hosts talk to Consul for service discovery. The cluster has 5 nodes, each serves a specific purpose. We want to easily scale up and down the number of &lt;code&gt;app&lt;/code&gt; containers.&lt;/p&gt;</description></item><item><title>Gmail Sending Limit</title><link>https://chengl.com/post/gmail-sending-limit/</link><pubDate>Fri, 08 Apr 2016 08:58:00 +0000</pubDate><guid>https://chengl.com/post/gmail-sending-limit/</guid><description>&lt;p&gt;Many people use Gmail as personal emails. Companies use &lt;a href="https://apps.google.com/"&gt;Google Apps for Work&lt;/a&gt;. Everyone is happy using it. Not until you hit its limits.&lt;/p&gt;
&lt;p&gt;I recently learnt &lt;a href="https://support.google.com/a/answer/166852?hl=en"&gt;its limits&lt;/a&gt; (shown below) in a hard way.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://chengl.com/content/images/2017/07/Screen-Shot-2016-04-08-at-3-33-16-PM.png" alt="Screen-Shot-2016-04-08-at-3-33-16-PM"&gt;&lt;/p&gt;
&lt;p&gt;I will hightlight the most restrictive constraints from the above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can send max 2000 emails per day from one account, &lt;strong&gt;500&lt;/strong&gt; for trial accounts&lt;/li&gt;
&lt;li&gt;3000 unique recipients per day, &lt;strong&gt;500&lt;/strong&gt; for trial accounts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From what I understand, normal Gmail accounts have the same limits as trial accounts. What are trial accounts? When you sign up &lt;a href="https://apps.google.com/"&gt;Google Apps for Work&lt;/a&gt;, all users are in trial period for 30 days. And it&amp;rsquo;s free during this period. After trial, you have to pay ~$5/user/month.&lt;/p&gt;</description></item><item><title>Life is Short. Run Tests in Parallel</title><link>https://chengl.com/post/life-is-short-run-tests-in-parallel/</link><pubDate>Sun, 20 Mar 2016 08:56:00 +0000</pubDate><guid>https://chengl.com/post/life-is-short-run-tests-in-parallel/</guid><description>&lt;p&gt;If you are doing Rails, chances are that you have &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; and &lt;a href="https://cucumber.io/"&gt;Cucumber&lt;/a&gt; tests. They are great tools to give you the confidence that your software is working as expected. But as project grows, you may find that your tests are getting slower and slower, expecially the Cucumber tests. It not only slows down the speed of your local development, but also your Continuous Integration pipeline (Test is probably the first stage in your CI). We don&amp;rsquo;t want to waste time waiting tests to finish in either local or CI. We want to develop and integrate faster. Here is how.&lt;/p&gt;</description></item><item><title>HTTP/2</title><link>https://chengl.com/post/http2/</link><pubDate>Mon, 14 Mar 2016 08:53:00 +0000</pubDate><guid>https://chengl.com/post/http2/</guid><description>&lt;h3 id="what-is-http2-and-why"&gt;What is HTTP/2 and Why&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://tools.ietf.org/html/rfc2068"&gt;HTTP/1.1&lt;/a&gt; has been serving most part of the Web since 1997. As websites get more and more sophisticated and resource intensive, it starts to show its limitations, e.g. one outstanding request per TCP connection. So its next-generation emerged: &lt;a href="http://http2.github.io/"&gt;HTTP/2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://http2.github.io/faq/"&gt;HTTP/2 FAQ&lt;/a&gt; does a great job explaining the background and specifications. Highly recommended. Here is an executive summary, HTTP/2:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is specifically designed to improve performance&lt;/li&gt;
&lt;li&gt;is based on &lt;a href="http://tools.ietf.org/html/draft-mbelshe-httpbis-spdy-00"&gt;SPDY&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;is binary, instead of textual&lt;/li&gt;
&lt;li&gt;is fully multiplexed, instead of ordered and blocking&lt;/li&gt;
&lt;li&gt;can therefore use one connection for parallelism&lt;/li&gt;
&lt;li&gt;uses header compression to reduce overhead&lt;/li&gt;
&lt;li&gt;allows servers to push responses proactively into client caches&lt;/li&gt;
&lt;li&gt;is backward-compatible, designed to be drop-in replacement for HTTP/1.1&lt;/li&gt;
&lt;li&gt;is &lt;a href="http://caniuse.com/#search=http%2F2"&gt;supported by most broswers over TLS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HttpWatch &lt;a href="https://blog.httpwatch.com/2015/01/16/a-simple-performance-comparison-of-https-spdy-and-http2/"&gt;reported&lt;/a&gt; good performance improvement by using HTTP/2.&lt;/p&gt;</description></item><item><title>Using Docker for Rails Development</title><link>https://chengl.com/post/using-docker-for-rails-development/</link><pubDate>Sun, 14 Feb 2016 08:49:00 +0000</pubDate><guid>https://chengl.com/post/using-docker-for-rails-development/</guid><description>&lt;h3 id="why"&gt;Why&lt;/h3&gt;
&lt;p&gt;There are many use cases of Docker. I see people primarily using it for Continous Integration and deployment. But Docker is also good for development. The obvious advantages of using Docker for development are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No need to install app dependencies on dev machines. App dependencies are built into Docker images. Hence, the dev machines are not messed up with crazy dependencies. The only dependency needed on dev machines is Docker, nothing else.&lt;/li&gt;
&lt;li&gt;Have a consistent development environment for all developers. No more excuse like &amp;ldquo;&lt;strong&gt;It works on my machine&lt;/strong&gt;&amp;rdquo;!&lt;/li&gt;
&lt;li&gt;Onboard new developers quickly. No need to spend hours setting up new dev machine and configuring it. You only need &lt;code&gt;docker-compose up&lt;/code&gt; and you can start coding.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="prerequisites"&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;This post will show you how to setup a Ruby on Rails development environment using Docker. My dev machine has&lt;/p&gt;</description></item><item><title>Let's Encrypt Nginx</title><link>https://chengl.com/post/lets-encrypt-nginx/</link><pubDate>Sun, 31 Jan 2016 08:41:00 +0000</pubDate><guid>https://chengl.com/post/lets-encrypt-nginx/</guid><description>&lt;p&gt;&lt;em&gt;Update [2017 Aug 5]: Certbot has been developed by EFF and others as an easy-to-use automatic client that fetches and deploys SSL/TLS certificates. I would recommend using &lt;a href="https://certbot.eff.org/"&gt;it&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="why"&gt;Why&lt;/h2&gt;
&lt;p&gt;Since you are here, you probably know what &lt;a href="https://letsencrypt.org"&gt;Let&amp;rsquo;s Encrypt&lt;/a&gt; is and why it exists. If not, below is an executive summary (copied from &lt;a href="https://letsencrypt.org/howitworks/"&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Anyone who has gone through the trouble of setting up a secure website knows what a hassle getting and maintaining a certificate can be. Let’s Encrypt automates away the pain and lets site operators turn on and manage HTTPS with simple commands.&lt;/p&gt;</description></item><item><title>Gradle Offline Build</title><link>https://chengl.com/post/gradle-offline-build/</link><pubDate>Sun, 20 Sep 2015 08:38:00 +0000</pubDate><guid>https://chengl.com/post/gradle-offline-build/</guid><description>&lt;h1 id="the-problem"&gt;The Problem&lt;/h1&gt;
&lt;p&gt;In a recent project, I have to do Gradle build on a CI server in a very constrained environment. The constraints are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NO Internet connection&lt;/li&gt;
&lt;li&gt;NO Gradle installed&lt;/li&gt;
&lt;li&gt;NO local Maven repo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The obvious problem that these constraints cause is that the project can&amp;rsquo;t build because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gradle is not installed&lt;/li&gt;
&lt;li&gt;Can&amp;rsquo;t get dependencies&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="the-solution"&gt;The Solution&lt;/h1&gt;
&lt;p&gt;This solution will achieve the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use Gradle to build&lt;/li&gt;
&lt;li&gt;Use Gradle to manage dependencies&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;rsquo;s solve the problem step by step.&lt;/p&gt;</description></item><item><title>Speed up bundle install</title><link>https://chengl.com/post/speed-up-bundle-install/</link><pubDate>Sat, 04 Apr 2015 08:36:00 +0000</pubDate><guid>https://chengl.com/post/speed-up-bundle-install/</guid><description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Next time, when you need &lt;code&gt;bundle install&lt;/code&gt;, do &lt;code&gt;bundle install --jobs X&lt;/code&gt;, where &lt;strong&gt;X&lt;/strong&gt; is the number of your machine cores. It will save you huge amount of time.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://archlever.blogspot.sg/2013/09/lies-damned-lies-and-truths-backed-by.html"&gt;Some blog&lt;/a&gt; suggests that setting the number of jobs to &lt;strong&gt;X-1&lt;/strong&gt; is statistically better than &lt;strong&gt;X&lt;/strong&gt;. But that is not true anymore, at least with bundler &amp;gt;= 1.7.12. To prove this, I tested it on a large Rails project (&lt;a href="https://github.com/discourse/discourse"&gt;discourse&lt;/a&gt;) on my Mid 2012 MBP with 2.6 GHz Intel Core i7. Below is my test result:&lt;/p&gt;</description></item><item><title>Less frequently used git commands</title><link>https://chengl.com/post/less-frequently-used-git-commands/</link><pubDate>Sun, 22 Mar 2015 08:30:00 +0000</pubDate><guid>https://chengl.com/post/less-frequently-used-git-commands/</guid><description>&lt;p&gt;From time to time, I find myself or my peers not using git correctly or efficiently. This is largely due to the fact that some git commands are less well known and used. Below are a few commands that could be helpful but less frequently used.&lt;/p&gt;
&lt;h4 id="git-bisect"&gt;git bisect&lt;/h4&gt;
&lt;p&gt;Suppose you find that commit &lt;code&gt;c100&lt;/code&gt; is failing your tests. But it was running fine at commit &lt;code&gt;c67&lt;/code&gt;. You want to know which commit in the range (&lt;code&gt;c67&lt;/code&gt;, &lt;code&gt;c100&lt;/code&gt;] introduced the bug.&lt;/p&gt;</description></item><item><title>Full Access to Mobile Technologies Is NOT a Previlege, It's a RIGHT</title><link>https://chengl.com/post/full-access-to-mobile-technologies-is-not-a-previlege-its-a-right/</link><pubDate>Sat, 28 Dec 2013 08:17:00 +0000</pubDate><guid>https://chengl.com/post/full-access-to-mobile-technologies-is-not-a-previlege-its-a-right/</guid><description>&lt;p&gt;It&amp;rsquo;s the end of 2013. I would like to share some thoughts on the new mobile trend.&lt;/p&gt;
&lt;p&gt;Several events happened in the second half of 2013:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.xiaomi.com/hongmi"&gt;hongmi&lt;/a&gt; is released for RMB799 (~$132) and become &lt;a href="http://weibo.com/xiaomihongmi"&gt;extremely popular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.motorola.com/us/shop-all-mobile-phones-1/Moto-G/moto-g-pdp.html"&gt;Moto G&lt;/a&gt; is &lt;a href="http://www.youtube.com/watch?v=4jrz4c0UDKY"&gt;released&lt;/a&gt; for $179&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.vmall.com/product/806.html#1175"&gt;Honor 3C&lt;/a&gt; is released for RMB798.00 (~$132). First batch was &lt;a href="http://tech.china.com/hardware/smartphone/11099080/20131225/18243646.html"&gt;sold out&lt;/a&gt; in 1 minute&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Look at these phones, they all have decent display, CPU, camera, etc. And considering their prices, I realize that their value to price ratio is ridiculously high.&lt;/p&gt;</description></item></channel></rss>