<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title></title>
    <description>The heisenbugger at work</description>
    <link>http://boopathi.in/blog/</link>
    <atom:link href="http://boopathi.in/blog/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sat, 28 Feb 2015 21:45:23 +0530</pubDate>
    <lastBuildDate>Sat, 28 Feb 2015 21:45:23 +0530</lastBuildDate>
    <generator>Jekyll v2.5.3</generator>
    
      <item>
        <title>Profiling Node.js applications on OSX</title>
        <description>&lt;p&gt;Note: ustack helpers don&amp;#39;t work at all on OSX. So the output you get from using dtrace on OSX would be of little help only. Use SmartOS or Illumos based OS to enjoy the advantage of ustack helpers and USDT probes. More about why it doesn&amp;#39;t work on OSX is explained nicely here&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/joyent/node/issues/3617&quot;&gt;https://github.com/joyent/node/issues/3617&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://dtrace.org/blogs/dap/2012/01/05/where-does-your-node-program-spend-its-time/&quot;&gt;http://dtrace.org/blogs/dap/2012/01/05/where-does-your-node-program-spend-its-time/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The happy flow:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make sure all dependencies are installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;g++ --version &lt;span class=&quot;c&quot;&gt;#preferably latest&lt;/span&gt;
make --version &lt;span class=&quot;c&quot;&gt;#preferably latest&lt;/span&gt;
python --version &lt;span class=&quot;c&quot;&gt;#Should be 2.6 or 2.7 (as required by node)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Download the &lt;strong&gt;Source Code&lt;/strong&gt; of the latest version of node from  &lt;a href=&quot;http://nodejs.org/download/&quot; title=&quot;http://nodejs.org/download/&quot;&gt;http://nodejs.org/download/&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extract the contents&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;tar xvzf node-v0.10.31.tar.gz &lt;span class=&quot;c&quot;&gt;#replace the filename if necessary&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;This is the most important part. You have to configure node build to be 32-bit and to use dtrace.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;./configure --with-dtrace --dest-cpu&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ia32
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Build node with the configured options and install.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;make
sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Go have a cup of coffee while make  is taking place.&lt;/li&gt;
&lt;li&gt;Verify node and npm installation&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;node --version
npm --version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Install stackvis - our flame graph generation tool. Use sudo  if required.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;npm install -g stackvis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Install your app dependencies. Insert the Nodejs dtrace probes and start your node application&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;npm install
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DTRACE_DOF_INIT_DEBUG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
  node app.js &amp;gt; console.log 2&amp;gt; error.log &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;#you can start it however you like&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Capture the profile using Dtrace. Dtrace requires additional privileges.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;sudo dtrace -n &lt;span class=&quot;s1&quot;&gt;&amp;#39;profile-97/execname == &amp;quot;node&amp;quot; &amp;amp;&amp;amp; arg1/{&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;  @[jstack(100, 8000)] = count(); } tick-60s { exit(0); }&amp;#39;&lt;/span&gt; &amp;gt; stacks.out
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Run stackvis on the captured stacks.out to generate the flame graph.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;stackvis dtrace &amp;lt; stacks.out &amp;gt; stacks.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Open stacks.html from your favourite browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Gotchas:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you start your node application with forever or pm2, it might not appear in the pstree as node. So you might have to change - &lt;code&gt;execname == &amp;quot;node&amp;quot;&lt;/code&gt;  to &lt;code&gt;pid == 12345&lt;/code&gt;  or &lt;code&gt;execname = &amp;quot;pm2&amp;quot;&lt;/code&gt;  or something similar.&lt;/li&gt;
&lt;li&gt;To get SVG, set the output type as flamegraph-svg.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;stackvis dtrace flamegraph-svg &amp;lt; stacks.out &amp;gt; stacks.svg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;I usually run my web app with &lt;code&gt;NODE_ENV=production&lt;/code&gt;, 4 processes on a 4 core machine using &lt;a href=&quot;http://nodejs.org/api/cluster.html&quot; title=&quot;cluster&quot;&gt;cluster&lt;/a&gt;,  and get profiles under the following conditions - 1. no load, 2. avg load - ( &lt;code&gt;ab -n50 -c3&lt;/code&gt; ), 3. high load ( &lt;code&gt;ab -n200 -c10&lt;/code&gt; ).&lt;/li&gt;
&lt;li&gt;Found something ? Comment on this post, and I&amp;#39;ll add them here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;
</description>
        <pubDate>Tue, 02 Sep 2014 19:30:34 +0530</pubDate>
        <link>http://boopathi.in/blog/profiling-node-js-applications-on-osx/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/profiling-node-js-applications-on-osx/</guid>
        
        <category>dtrace</category>
        
        <category>nodejs profiling</category>
        
        <category>osx</category>
        
        
        <category>javascript</category>
        
        <category>nodejs</category>
        
        <category>osx</category>
        
        <category>tips and tricks</category>
        
      </item>
    
      <item>
        <title>Dockerfile for golang applications</title>
        <description>&lt;h2&gt;A few headers&lt;/h2&gt;

&lt;p&gt;We will assume that we are deploying our applications on Ubuntu.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-Dockerfile&quot; data-lang=&quot;Dockerfile&quot;&gt;    FROM ubuntu:12.04
    MAINTAINER My Name &amp;lt;me@domain.tld&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Install dependencies&lt;/h2&gt;

&lt;h3&gt;Add Mercurial Repository (if necessary)&lt;/h3&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;# Mercurial
RUN echo &amp;#39;deb http://ppa.launchpad.net/mercurial-ppa/releases/ubuntu precise main&amp;#39; &amp;gt; /etc/apt/sources.list.d/mercurial.list
RUN echo &amp;#39;deb-src http://ppa.launchpad.net/mercurial-ppa/releases/ubuntu precise main&amp;#39; &amp;gt;&amp;gt; /etc/apt/sources.list.d/mercurial.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 323293EE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Install dependencies&lt;/h3&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;RUN apt-get update
RUN apt-get install -y curl git bzr mercurial
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Curl is required to download Go tar ball.&lt;/li&gt;
&lt;li&gt;git, bazaar and mercurial are used by go get to download your application dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Install Go&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;RUN curl -s https://go.googlecode.com/files/go1.2.linux-amd64.tar.gz | tar -v -C /usr/local/ -xz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Configure Environment for Go&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ENV PATH /usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
ENV GOPATH /go
ENV GOROOT /usr/local/go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Hack - To cache go get&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;RUN go get github.com/myname/my-golang-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is called immediately before adding the project files to the repo and essentially before performing a &lt;code&gt;go get&lt;/code&gt; from inside the repo&amp;#39;s directory within the container. Docker&amp;#39;s ADD doesn&amp;#39;t support caching until 0.7.3. Adding the source files to the container and then performing a go get doesn&amp;#39;t utilize the cache. It downloads all the dependencies once again and is time consuming.&lt;/p&gt;

&lt;h2&gt;Add source files to the container&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;WORKDIR /go/src/github.com/myname/my-golang-project
ADD . /go/src/github.com/myname/my-golang-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Fetch new dependencies if any&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;RUN go get
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Install application&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;RUN go build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;If your app exposes a port, expose it&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;EXPOSE 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Set entrypoint&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ENTRYPOINT ./my-golang-project -option value args
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you set the entrypoint in docker, the entire container behaves as if it was that single application/executable. You can daemonize this with docker run -d .&lt;/p&gt;

&lt;h1&gt;A simpler method&lt;/h1&gt;

&lt;p&gt;I have done the first few parts and pushed it to index.docker.io. You can create your image with that as the base image. And this is how you do it.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;FROM boopathi/go:latest
MAINTAINER myname &amp;lt;emailaddress&amp;gt;
WORKDIR /go/src/github.com/myname/my-golang-repo
RUN go get github.com/myname/my-golang-repo
ADD . /go/src/github.com/myname/my-golang-repo
RUN go get
RUN go build
EXPOSE 8080
ENTRYPOINT ./my-golang-project -option value args
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Links&lt;/h2&gt;

&lt;p&gt;Go dev environment docker image:  &lt;a href=&quot;https://index.docker.io/u/boopathi/go/&quot;&gt;https://index.docker.io/u/boopathi/go/&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 17 Jan 2014 15:09:58 +0530</pubDate>
        <link>http://boopathi.in/blog/dockerfile-for-golang-applications/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/dockerfile-for-golang-applications/</guid>
        
        <category>deploy</category>
        
        <category>docker</category>
        
        <category>go</category>
        
        <category>golang</category>
        
        
        <category>automation</category>
        
        <category>docker</category>
        
        <category>go</category>
        
      </item>
    
      <item>
        <title>A fancy timeout in bash</title>
        <description>&lt;p&gt;Timing-out-and-moving-on is a programming paradigm generally followed in many multi-process or multi-threaded programs. In a scripting environment like bash, the solution is to do this in a hacky way. Of course coreutils now provides a tool called &amp;quot;timeout&amp;quot; which does exactly what we need - Run the command and timer concurrently. Whenever something exits, the other one gets killed.&lt;/p&gt;

&lt;p&gt;Bash is all about finding amazing ways to do things. Here is one of them.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;sh -ic &lt;span class=&quot;s2&quot;&gt;&amp;quot;{ sleep $T1; echo one &amp;gt;&amp;amp;3; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;  kill 0; } | { sleep $T2; echo two &amp;gt;&amp;amp;3; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;  kill 0; }&amp;quot;&lt;/span&gt; 3&amp;gt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt; Internals:&lt;/h2&gt;

&lt;p&gt;Going from inside out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In bash &lt;code&gt;{ some command; }&lt;/code&gt;  represents a block of code or &lt;strong&gt;inline group&lt;/strong&gt; ( &lt;a href=&quot;http://tldp.org/LDP/abs/html/special-chars.html#CODEBLOCKREF&quot;&gt;http://tldp.org/LDP/abs/html/special-chars.html#CODEBLOCKREF&lt;/a&gt; ). This construct creates an anonymous function and all the processes invoked come under the same &lt;strong&gt;process group&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The structure of the invoked script is &lt;code&gt;{ } | { }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each inline group has a &lt;code&gt;kill 0;&lt;/code&gt;  . The man page of kill says that &lt;code&gt;kill 0&lt;/code&gt; signals all processes in the &lt;em&gt;current&lt;/em&gt; process group.&lt;/li&gt;
&lt;li&gt;When you do &lt;code&gt;kill 0;&lt;/code&gt;  all that happens is the shell will start a new job to execute that kill command, so kill  will only kill itself.&lt;/li&gt;
&lt;li&gt;All the processes invoked inside &lt;code&gt;{ }&lt;/code&gt;  will be under the same process group, so &lt;code&gt;kill 0&lt;/code&gt; would work there.&lt;/li&gt;
&lt;li&gt;Note the output redirection &lt;code&gt;&amp;gt;&amp;amp;3&lt;/code&gt; within each of the inline groups. Here, we are writing the output to a different file descriptor identified by &lt;code&gt;3&lt;/code&gt;. &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; are already defined as &lt;code&gt;STDOUT&lt;/code&gt; and &lt;code&gt;STDERR&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This file descriptor &lt;code&gt;3&lt;/code&gt; is used to communicate with the outside world. Since there is a pipe between the two inline groups, the output of first group cannot be captured - It goes as input to the second inline group. You have to either write it to a file or a stream represented by a file descriptor.&lt;/li&gt;
&lt;li&gt;Just for clarity, I&amp;#39;ve used &lt;code&gt;&amp;gt;&amp;amp;3&lt;/code&gt;  in both the inline groups. Capturing the output in fd3 outside this setup.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sh -ic &amp;quot;&amp;quot;&lt;/code&gt;  creates a sub-shell and runs the command that&amp;#39;s passed as argument. The &lt;code&gt;-i&lt;/code&gt;  flag is to run interactively.&lt;/li&gt;
&lt;li&gt;Within this sub-shell, we have our two inline groups sending necessary outputs to fd3. So outside this sub-shell (running  &lt;strong&gt;interactively&lt;/strong&gt; ) we can capture fd3 and redirect it however required&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3&amp;gt;&amp;amp;1&lt;/code&gt;  fd3 is redirected to STDOUT of the session from which the sub-shell is invoked.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Putting everything together: (the short version)&lt;/h2&gt;

&lt;p&gt;Create a new sub-shell to run interactively. Within this sub-shell, create an inline group that outputs to fd3. Pipe this inline group to another inline group which also outputs to fd3. In the session which invoked the sub-shell, redirect fd3 to &lt;code&gt;STDOUT&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Why does this work ?&lt;/h2&gt;

&lt;p&gt;All that we are doing is pipe two inline groups. One of the inline groups contain our main program which shouldn&amp;#39;t run longer than &lt;code&gt;$TIMEOUT&lt;/code&gt; . The other inline group would sleep for &lt;code&gt;$TIMEOUT&lt;/code&gt; - both followed by a &lt;code&gt;kill 0;&lt;/code&gt; statement. Whichever exits first is going to call the kill command and all the processes in that process group will be killed. This includes the sub-shell and all the processes within the sub-shell.&lt;/p&gt;

&lt;h2&gt;Example:&lt;/h2&gt;

&lt;p&gt;Capture bandwidth usage per process using nethogs for 1 hour.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;sh -ic &lt;span class=&quot;s2&quot;&gt;&amp;quot;{ /usr/sbin/nethogs -t &amp;gt;&amp;amp;3; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;  kill 0; } | { sleep 3600; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;  kill 0; }&amp;quot;&lt;/span&gt; 3&amp;gt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;More about this is discussed here  -  &lt;a href=&quot;http://boopathi.in/blog/capturing-per-process-bandwidth-usage-using-nethogs&quot;&gt;http://boopathi.in/blog/capturing-per-process-bandwidth-usage-using-nethogs&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Wed, 15 Jan 2014 19:02:34 +0530</pubDate>
        <link>http://boopathi.in/blog/a-fancy-timeout-in-bash/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/a-fancy-timeout-in-bash/</guid>
        
        <category>bash</category>
        
        <category>process groups</category>
        
        <category>system administraion</category>
        
        <category>timeout</category>
        
        <category>unix</category>
        
        
        <category>system administration</category>
        
        <category>unix</category>
        
      </item>
    
      <item>
        <title>Capturing per process bandwidth usage using nethogs</title>
        <description>&lt;p&gt;On some of our servers at directi, we capture the bandwidth per process using nethogs on an interface over a period of time. The official description of nethogs from its author is as follows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://nethogs.sourceforge.net/&quot;&gt;http://nethogs.sourceforge.net/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NetHogs is a small &amp;#39;net top&amp;#39; tool. Instead of breaking the traffic down per protocol or per subnet, like most tools do, it groups bandwidth by process. NetHogs does not rely on a special kernel module to be loaded. If there&amp;#39;s suddenly a lot of network traffic, you can fire up NetHogs and immediately see which PID is causing this. This makes it easy to indentify programs that have gone wild and are suddenly taking up your bandwidth.Since NetHogs heavily relies on /proc, it currently runs on Linux only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;The -t parameter : Trace mode&lt;/h2&gt;

&lt;p&gt;This is the bug-hunt mode. You enable it and collect the output stream over a period of time. From this log you calculate the necessary results. Nethogs refreshes every second and gives the output in &lt;code&gt;kbps&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;How ?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start nethogs to listen on some interface and grab the output to some file.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;    /usr/sbin/nethogs -t eth1 &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&amp;gt; output
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Now you might want to run this in the background. And the solution is going to be simple.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;    nohup /usr/sbin/nethogs -t eth1 &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&amp;gt; output &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;But remember that, that script is going to run forever unless you manually kill it. Now you have to follow the time-out-and-move-on paradigm. There are many ways to do it in bash, but the simplest and most efficient way is this:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;    sh -ic &lt;span class=&quot;s2&quot;&gt;&amp;quot;{ /usr/sbin/nethogs -t eth1 &amp;amp;&amp;gt; output; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    kill 0; } | { sleep $TIMEOUT; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    kill 0; }&amp;quot;&lt;/span&gt; 3&amp;gt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;The output:&lt;/h2&gt;

&lt;p&gt;The output of the nethogs tracemode will be something like this.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Refreshing:
/usr/sbin/exim/689041/47 0.0167969 0.289844
10.10.10.10:80-11.11.11.11:58485/0/0 0.0105469 0.194141
pop3/703049/2926 2.46855 0.140625
/usr/local/apache/bin/httpd/700895/99 4.44023 0.0949219
/usr/local/apache/bin/httpd/669759/99 1.69883 0.0832031
/usr/local/apache/bin/httpd/678264/99 1.71016 0.0738281
/usr/local/apache/bin/httpd/673811/99 2.99844 0.0730469
/usr/local/apache/bin/httpd/578292/99 0.588281 0.0621094
unknown TCP/0/0 0.855469 0.0503906
/usr/local/apache/bin/httpd/701327/99 3.65273 0.046875
pure-ftpd (PRIV)/680421/0 0.0574219 0.0460938
imap-login/88707/97 0.0183594 0.0271484
sshd: boopathi@pts/7/656215/32076 0.0730469 0.0222656
12.12.12.12:80-13.13.13.13:58271/0/0 0 0.0144531
/usr/local/apache/bin/httpd/677948/99 0.291797 0.0117188
Unknown connection: 60.60.60.60:80-66.66.66.66:36813
Unknown connection: 100.200.105.205:80-65.56.56.56:42293
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And the fields (for the lines that are not either a warning or an error) are&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Process / Process id / User id    sent kbps    recv kbps
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Parser&lt;/h2&gt;

&lt;p&gt;Source code: &lt;a href=&quot;https://github.com/boopathi/nethogs-parser&quot; title=&quot;Nethogs-Parser&quot;&gt;https://github.com/boopathi/nethogs-parser&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Automating&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s take into consideration the output stream of nethogs - specifically number of bytes per second and assume that the file size will not be too high for logs fetched over a particular time period. Let&amp;#39;s fix this as 1hour. So, for 1hour nethogs is going to listen on some interface and for the next hour a new process will be invoked. The simplest way to do is to write the script that will run for an hour and call it in an hourly cron.&lt;/p&gt;

&lt;h3&gt;monitor.sh:&lt;/h3&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;    &lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;


    &lt;span class=&quot;nv&quot;&gt;TIMEOUT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3600
    &lt;span class=&quot;nv&quot;&gt;IFACE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;eth0
    &lt;span class=&quot;nv&quot;&gt;TIMESTAMP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;date +%b_%d_%Y_%H_%M_%S&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;OUTPUT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/var/log/nethogs/&lt;span class=&quot;nv&quot;&gt;$TIMESTAMP&lt;/span&gt;.log


    sh -ic &lt;span class=&quot;s2&quot;&gt;&amp;quot;{ /usr/sbin/nethogs -t $IFACE &amp;amp;&amp;gt;$OUTPUT; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    kill 0; } | { sleep $TIMEOUT; \&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;    kill 0; }&amp;quot;&lt;/span&gt; 3&amp;gt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt; cron: /etc/cron.d/nethogs.cron&lt;/h3&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;0 5,6,7,10,11,20,21 * * *    root    /path/to/monitor.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
</description>
        <pubDate>Wed, 15 Jan 2014 13:05:01 +0530</pubDate>
        <link>http://boopathi.in/blog/capturing-per-process-bandwidth-usage-using-nethogs/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/capturing-per-process-bandwidth-usage-using-nethogs/</guid>
        
        <category>bandwidth</category>
        
        <category>nethogs</category>
        
        <category>per-process</category>
        
        <category>system administration</category>
        
        
        <category>bandwidth</category>
        
        <category>linux</category>
        
        <category>system administration</category>
        
        <category>tips and tricks</category>
        
      </item>
    
      <item>
        <title>The Graphite story @ Directi</title>
        <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At Directi, we use &lt;a href=&quot;http://github.com/graphite-project/graphite-web&quot; title=&quot;Graphite&quot;&gt;graphite&lt;/a&gt; as one of our principal monitoring tools. Initially, when Graphite set its foot into the company&amp;#39;s monitoring system, the setup was a cinch where one server was dedicated to receive metrics data, render the graphs and serve it to the requesting users. The problem with this setup was pretty much like a talking turkey, that it hit the bottleneck when the amount of metrics sent to this server became significantly high. This&amp;#39;d result in carbon-relay and carbon-cache instances on the system consuming a lot of CPU and Memory leaving not much resources available for the webapp and WSGI Daemon to use. This indubitably resulted in performance issues with rendering the graphs. It literally took a minute to render each graph. And when we perform some functions(provided by graphite) over the graph data, it&amp;#39;d almost take a minute and a half or more to render the graph. I&amp;#39;d have a coffee-break in the time my dashboard loads.&lt;/p&gt;

&lt;p&gt;The primary bottleneck that we were facing was the disk I/O - as faced by every damn graphite beginner out there in the dev-ops team. So we decided to use SSDs on the server. But, it wouldn&amp;#39;t be a cheap solution to replace all rotational drives with SSDs, because, we&amp;#39;d require a hell a lot of storage to store that much amount of whisper data. But we didn&amp;#39;t want to sacrifice the power and advantage of SSDs. &lt;a href=&quot;http://github.com/facebook/flashcache&quot; title=&quot;Flashcache&quot;&gt;Flashcache&lt;/a&gt; came to the rescue. Flashcache is a block-cache for Linux. It helps extending Linux block-cache with a SSD drive. It is cheaper than buying half a TB of RAM and 5 TB of SSD drives. After a few tests and try-outs with flashcache, we decided to use write-back caching mode. In write-back mode, all writes go to the cachedev (SSDs) initially, and based on few policies, they are written to the disk later. All disk reads are cached. It&amp;#39;s determined and documented to be the fastest mode to write and is pretty unsafe. We really didn&amp;#39;t care much about the safety of the data received, because, even if we lose a few metric points, it&amp;#39;s not that big a deal to be significantly important.&lt;/p&gt;

&lt;p&gt;Once flashcache was up and doing its work properly, we started to enjoy the bounty of the performance improvements with respect to IOPS. During this time, metrics were sent from 100s of servers, and the maximum number of metrics per minute reached a value of 300k. A single carbon-relay instance was able to handle this much load i.e. it held the incoming metrics in its queue and relayed it to the 3 carbon-cache instances on the same system. At this time, relay was not our bottleneck. Meanwhile, when planning to experiment and expand this setup to serve greater extents, we faced this NFC (abbreviated as No F**king Clue) issue with flashcache - Kernel Panic on system reboot OR halt. Every time we rebooted graphite server, during halt scripts&amp;#39; execution, KERNEL panic occurs. NFC!!!. It&amp;#39;s not that easy to understand the Kernel Panic logs the first time you see it. It&amp;#39;s exactly the same thing as reading a bunch of scattered items from a pool of hexadecimal values. Investigating further, we developed experience on &amp;quot;How to&amp;quot; and &amp;quot;How not to&amp;quot; use flashcache, but none of these solved our Kernel panic issue. Finally, there came a moment, where we had to dig through Linux&amp;#39;s halt process and confirmed that flashcache was the culprit. When the halt process was happening, removing the Logical Volume using dmsetup wouldn&amp;#39;t happen automatically. The halt script would just try to unmount whatever is on its way to completing the shutdown process. So we plugged in a SysVInit script as a hook that is invoked by the halt script when it sees a flag for flashcache in subsys. This init script is responsible for loading and removing the LV. While removing we need to consider whether or not to sync the data between the cache and the backend disk. This is determined by the sysctl flag &amp;quot;fast&lt;em&gt;remove&amp;quot;. However, the default behaviour on a remove is to clean the dirty cache blocks to disk and the remove will not return until all blocks are cleaned OR in simple terms - Setting the fast&lt;/em&gt;remove option to 0, flushes the cached data to the backend disk and setting it to 1, the cache would still have uncommitted dirty blocks. A little more on tweaking flashcache could be found in my other blog post -  &lt;a href=&quot;http://boopathi.in/blog/flashcache-blah-blah&quot; title=&quot;flashcache-blah-blah&quot;&gt;http://boopathi.in/blog/flashcache-blah-blah&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With this setup, the graphite server with a dozen cores CPU, and a dozen gigs of Memory was receiving and replying fairly well for sometime until we hit the next bottleneck with carbon-relay process. At an average, the graphite server received 300k metrics, and the sender script used plain TCP connection for every line of the metric. We didn&amp;#39;t require aggregation for most of the metrics, since preserving the individual values mattered. The problem with the Carbon agents was that the number of file descriptors got exhausted and they were not able to open any more files to write to. This resulted in an increase in the queue size of relay. And this hit the limit as set in carbon.conf under relay section. I remember the queue size to be around 5000 data points. At this point, relay started throwing errors onto its console. The error said - &amp;quot;Could not accept new connection (EMFILE)&amp;quot;. EMFILE refers to the shortage of file descriptors available to that particular process, here, carbon-cache. So, we increased the ulimit from 1024 to 4096 for the session that initiated the carbon-daemons. But this wasn&amp;#39;t sufficient. So, we increased it to 10240, and increased the queue size to 10000. The relay started accepting connections, and everything was back to normal. Not so fast buddy? To where? A stable graphite setup ? Huh. You know that&amp;#39;s insanity. By the time we realized that we had to handle a larger load, relay started trembling again. The root cause for this was a bug in the metric collector scripts. The collector scripts works in a way that it doesn&amp;#39;t send to graphite immediately. We do some caching on every client system, where we write all the collected metrics to a temporary device, and a cron reads the cached metrics and flushes it to the graphite server. When this cron is not able to establish the TCP connection, the metrics remain in the cache file  - cluttering. When the bug was fixed, the amount of cached metrics emerging from 100s of servers was more than twice the average value (around 800k). At this point, relay had no other choice but to stop accepting metrics. A quick fix that we discovered was to restart relay when the number of metrics it accepts goes below a critical value. After some analysis, 4hrs seemed to be a fair value. So we kept restarting relay every 4 hours, a graph of which would explain the failure of the process gradually.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://boopathi.in/blog/assets/img/relay-Copy.png&quot;&gt;&lt;img src=&quot;/blog/assets/img/relay-Copy.png&quot; alt=&quot;relay&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this way, we reached to some arbitrary solution, where we tweaked the collector scripts to send lesser number of metrics. At this point, it&amp;#39;s quite obvious that graphite server was hitting the bottleneck every 4 hours. The average amount of metrics received is around 300k, but the graph shows 750k metrics everytime carbon-relay starts accepting all the connections made to it. The reason for this to happen is the caching mechanism we follow on the client systems. So all those metrics which failed to get into graphite would still be there on the clients. The next cron would try to push it, but graphite just wouldn&amp;#39;t accept any more connections. So when relay is restarted, graphite starts fresh, and memory is literally empty where it can accept all the connections made to it. That&amp;#39;s why we could see a spike to 750k data points every time relay starts fresh.&lt;/p&gt;

&lt;p&gt;Moving on the the next step in optimizing, we decided to put relay on a separate system, so that carbon-cache would have enough system resources to write to whisper files, while, on the other hand, relay would also have enough system resources to maintain a larger queue size as well as accept a larger number of connections. So we cloned relay to a new system graphite02 which was an exact clone (in system configuration) of graphite01. We initiated relay on graphite02, and it seemed to have solved the problem. All the cached metrics were accepted by the graphite02 relay continuously without any interrupts and they were relayed to carbon-cache instances on graphite01. A graph of that found below would explain that the area covered by the red lines was the initial load that graphite01 should have bared to be stable.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://boopathi.in/blog/assets/img/relay.png&quot;&gt;&lt;img src=&quot;/blog/assets/img/relay.png&quot; alt=&quot;relay&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An obvious analogy corresponding to the area mapped and area unmapped between two spikes can be found to correlate with the area mapped by the red region. And after all the cached metrics are sent, the rate of metrics reception becomes normal to a value of 200k per min. So, as mentioned earlier, all that graphite needed to handle was the initial spike (cached data points).&lt;/p&gt;

&lt;p&gt;Here comes the situation, where we feel that we aren&amp;#39;t using the system resources completely. We had two servers dedicated to monitoring, each had a dozen cores CPU and a dozen gigs of RAM, and SSDs and flashcache. So the next thing to try is to make this setup a cluster and load balance the carbon-agents and the webapp. Initial thoughts was to make it a High Availability cluster using corosync. But, we wanted to do things simpler than that. Graphite, by itself, provides a mechanism to load balance all the services and the webapp. They call it &amp;quot;The Federated Graphite Setup&amp;quot;. We read through some of the blog posts and launchpad answers and started tweaking carbon.conf and local_settings.py in graphite webapp. The graphite cluster now contained two servers, each running a relay, three carbon-cache instances, and the graphite webapp. Flashcache was setup on graphite02 too in a similar manner as present in graphite01. The relays are configured to feed its queue to all the 6 carbon-cache instances on the two systems. The issue is to determine which relay would serve the need, but the aim is to use both the relays. First tryout was that one relay(graphite01) received the metrics and relayed them to the relay on the other system(graphite02) and this load balanced between the 6 carbon-caches. The relay on graphite01 was configured to occupy more memory - bigger queue, and relay on graphite02 (second stage) was configured to occupy a lesser memory. This setup wasn&amp;#39;t that appreciable. So we decided to load balance before the data points reach relay. HAProxy solved our issue. We configured HAProxy to load balance between graphite01 relay and graphite02 relay, each of which would further load balance between 6 carbon-caches.&lt;/p&gt;

&lt;p&gt;Our next issue was with syncing the old metrics to the new system. We hit one more bottleneck where syncing between two production systems that is live becomes impractical. The root cause for this problem is the load balancing technique used. We used roundrobin in HAProxy and consistent-hashing in graphite relay. To understand consistent-hashing, consider the 6 carbon-cache instances to be the slots and the data-points to be the keys K. So, on an average only K/6 keys need to be remapped. This splits the relay&amp;#39;s incoming load almost equally to the 6 carbon-caches. On seeing a data-point, carbon would know where it&amp;#39;d get relayed to. (perks of consistent-hashing). Some of the metrics got relayed to graphite02 creating new files on graphite02 while leaving the files on graphite01 untouched. The old data which was already present on graphite01 should be merged with the new incoming metrics which didn&amp;#39;t happen automatically. Also graphite has this sick mechanism that if a whisper file is present in the same system the webapp is running, it wouldn&amp;#39;t query the other systems for the data. So the only way to solve this issue is to copy the old data to the new system, apply the consistent hash manually upon all the files, and unlink them if they don&amp;#39;t belong there. But we hit the bottleneck right at the first step - syncing data between the two servers. Started rsyncing the data, and estimated the time to complete. The value that appeared really shook my head - 10 days, which is impractical to be done on a live production system. So we decided to keep only few important metrics, rsync them and clean the files based on consistent hashing applied by carbon. The syncing was done, and some of the important metrics were retained, and the performance of the cluster was amazing that it could handle 4x load. We also increased the number of carbon-cache instances to 6 on each system. I would like to share an infographic of our setup.&lt;/p&gt;

&lt;p&gt;_ &lt;a href=&quot;http://boopathi.in/blog/assets/img/image.gif&quot;&gt;&lt;img src=&quot;/blog/assets/img/image.gif&quot; alt=&quot;graphiteinfo&quot;&gt;&lt;/a&gt;_&lt;/p&gt;

&lt;p&gt;I know it&amp;#39;s a very long post. One of the conclusions that we arrived at one point was to completely chuck graphite as the monitoring system, and use OpenTSDB. But it doesn&amp;#39;t provide enough functions like graphite does. And graphite is a really good project that I just can&amp;#39;t let it go. Now I&amp;#39;m trying out ceres database to use it in the place of whisper. Will blog about the same some time later ;). Thank you for reading till here.&lt;/p&gt;
</description>
        <pubDate>Wed, 27 Mar 2013 16:14:31 +0530</pubDate>
        <link>http://boopathi.in/blog/the-graphite-story-directi/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/the-graphite-story-directi/</guid>
        
        <category>carbon</category>
        
        <category>carbon-cache</category>
        
        <category>carbon-relay</category>
        
        <category>dev-ops</category>
        
        <category>directi</category>
        
        <category>federated graphite</category>
        
        <category>flashcache</category>
        
        <category>graphite</category>
        
        <category>graphite-web</category>
        
        <category>system administration</category>
        
        <category>whisper</category>
        
        <category>whisper db</category>
        
        
        <category>flashcache</category>
        
        <category>graphite</category>
        
        <category>system administration</category>
        
      </item>
    
      <item>
        <title>Writing your own JavaScript build system</title>
        <description>&lt;p&gt;I&amp;#39;m assuming that Google Closure compiler is one of the best JS compilers, and ll be using their API &amp;quot; &lt;a href=&quot;http://closure-compiler.appspot.com&quot; title=&quot;closure-compiler&quot;&gt;closure-compiler.appspot.com&lt;/a&gt;&amp;quot; in this tutorial. Also, I&amp;#39;m going to assume that you must be writing coffee-script and you have &lt;a href=&quot;http://coffeescript.org/&quot; title=&quot;Coffee Script&quot;&gt;coffee-script&lt;/a&gt; compiler pre-installed on your system. Don&amp;#39;t get demotivated or threatened by seeing the words &amp;quot;build system&amp;quot;. We are actually making a script that automates the final step in our development process, and makes the workflow a little swifter.&lt;/p&gt;

&lt;p&gt;The gist of this is, we write coffee-script, use coffee-script compiler to compile our code to plain JavaScript, we feed this JS code to Google Closure Compiler along with the link to libraries that our code depends on, we get the output from the &lt;a href=&quot;https://developers.google.com/closure/compiler/docs/gettingstarted_api&quot;&gt;Google Closure Compiler API&lt;/a&gt;, and we export that to a file in our repository.&lt;/p&gt;

&lt;h2&gt;1. Coffee-Script to JavaScript&lt;/h2&gt;

&lt;p&gt;From various resources and a little of personal experience, the conclusion is - the &lt;a href=&quot;http://docs.python.org/2/library/subprocess.html&quot;&gt;subprocess&lt;/a&gt; module in Python suits the need fairly well.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/usr/bin/coffee&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;-cp&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./path/to/file.coffee&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Popen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PIPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;js_code_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;communicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code is pretty much simple and is self explanatory. For those who are not familiar with Python, the gist of the above code is this&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;    execute the command &amp;#39;/usr/bin/coffee -cp ./path/to/file.coffee&amp;#39;
    grab the output to some variable instead of throwing it to the system STDOUT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;2. Grab plain JavaScript&lt;/h2&gt;

&lt;p&gt;This can be viewed in two ways. One is that you don&amp;#39;t write coffee-script. The other is, you write some coffee-script and then you&amp;#39;d want to add some plain JavaScript too. Once again, if you&amp;#39;re not familiar with Python, grab the file contents to some variable. Python users, this might be one of the best ways to grab file contents into a variable.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./path/to/script.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;javascript_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;js_code_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;javascript_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt; 3. Collecting dependencies&lt;/h2&gt;

&lt;p&gt;This section is just blah. You&amp;#39;ve to fetch the URLs of the libraries that you use. It doesn&amp;#39;t matter if that is not a minified version. Google Closure Compiler would handle that for you. If you don&amp;#39;t have a permalink to your library, clone that to your system and follow the previous step to grab it&amp;#39;s contents.&lt;/p&gt;

&lt;h2&gt;4. Sending request to Google Closure Compiler API&lt;/h2&gt;

&lt;p&gt;Send a HTTP - POST request to &amp;#39;closure-compiler.appspot.com/compile&amp;#39; with the content-type &amp;quot;application/x-www-form-urlencoded&amp;quot;. Grab the response to some variable. This would represent the minified/compiled JS code. Now you can throw this to some file.&lt;/p&gt;

&lt;p&gt;The following POST variables are important while requesting the API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;code_url : the permalink to your library code&lt;/li&gt;
&lt;li&gt;js&lt;em&gt;code : the contents - plain JavaScript code. ( js&lt;/em&gt;code&lt;em&gt;1  and js&lt;/em&gt;code_2  from the previous sections)&lt;/li&gt;
&lt;li&gt;compilation&lt;em&gt;level : &amp;#39;SIMPLE&lt;/em&gt;OPTIMIZATIONS&amp;#39; . Refer the API for more options.&lt;/li&gt;
&lt;li&gt;output_format : &amp;#39;text&amp;#39;&lt;/li&gt;
&lt;li&gt;output&lt;em&gt;info : &amp;#39;compiled&lt;/em&gt;code&amp;#39;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Download and Use:&lt;/h2&gt;

&lt;p&gt;Have uploaded a sample working Python code.  &lt;a href=&quot;https://gist.github.com/boopathi/4944562&quot;&gt;https://gist.github.com/boopathi/4944562&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get the script,&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;    wget https://gist.github.com/boopathi/4944562/raw/3bd83077ef3081eaedc5d74712a09fc0981e8f1d/jscompile.py &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chmod +x jscompile.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
</description>
        <pubDate>Wed, 13 Feb 2013 18:53:31 +0530</pubDate>
        <link>http://boopathi.in/blog/writing-your-own-javascript-build-system/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/writing-your-own-javascript-build-system/</guid>
        
        <category>javascript</category>
        
        <category>js builder</category>
        
        <category>minify</category>
        
        <category>python</category>
        
        
        <category>javascript</category>
        
        <category>python</category>
        
        <category>snippets</category>
        
        <category>tips and tricks</category>
        
        <category>web development</category>
        
      </item>
    
      <item>
        <title>Prototypes can&#39;t talk to local variables in the constructor</title>
        <description>&lt;p&gt;You can create local variables via a closure but then you&amp;#39;d have problems with inheritance.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//now&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;decrement&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//will be undefined :)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, this might not seem weird unless you compare it with some other programming language where Object Orientation is proper and true.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;    class counter {
    private: int count;
    public:
      void increment() { count++; }
      void decrement();
    }
    void counter::decrement { count--; } //count is not undefined.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;JavaScript is not a queer creature. There is no actual OOP in the language. The scope is what that helps us in simulating Object Orientation. Well, to make that work with JavaScript, you could use something like,&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//now&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;decrement&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// yes, you have to use `this` in javascript a lot!&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// using the &amp;quot;class&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;decrement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// -1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Keep in mind that, certain aspects won&amp;#39;t be enforced by the language itself, but instead provided as a syntactic sugar. The bottom line is that, when you write some code that plugs into a browser, you need not worry about protecting variables from the user. He can anyway peep in and do nasty things if he wishes. This might be a concern in environments like NodeJS.&lt;/p&gt;
</description>
        <pubDate>Wed, 13 Feb 2013 16:10:22 +0530</pubDate>
        <link>http://boopathi.in/blog/prototypes-cant-talk-to-local-variables-in-the-constructor/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/prototypes-cant-talk-to-local-variables-in-the-constructor/</guid>
        
        <category>abstraction</category>
        
        <category>inheritance</category>
        
        <category>javascript</category>
        
        <category>prototype</category>
        
        
        <category>javascript</category>
        
        <category>web development</category>
        
      </item>
    
      <item>
        <title>Flashcache - Blah blah</title>
        <description>&lt;p&gt;We were recently testing  &lt;a href=&quot;http://www.quora.com/Flashcache&quot;&gt;Flashcache&lt;/a&gt; on one of our servers at Directi. From various resources over the web, and from a little of my personal experience, I&amp;#39;m writing this post about flashcache.&lt;/p&gt;

&lt;p&gt;Flashcache, for those who haven&amp;#39;t seen before, by definition, is a block-cache for Linux. That just means - it&amp;#39;s a method for extending Linux block-cache with SSDs, by which, we save a few bucks avoiding half a TB of RAM just for caching. The performance is determined by various factors. In an abstraction, I&amp;#39;d tell these factors are important -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the size of the SSDs (best performance is obtained if the size of your SSDs is larger than the active-set of blocks. And, if you get perfect caching, the performance will be similar to running your entire system on SSDs) ,&lt;/li&gt;
&lt;li&gt;the estimate of reads and writes,&lt;/li&gt;
&lt;li&gt;flush frequency (when the writes are set to flush immediately - in case of file-system ops and db ops, caching is briefly done and performance will not be affected by the presence of flashcache).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Some internals:&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/CPU_cache&quot;&gt;CPU cache&lt;/a&gt; - The Linux-block cache works in a manner that it caches  &lt;strong&gt;accessed blocks&lt;/strong&gt;  and NOT files. So long as you&amp;#39;re not giving your program / some KVM direct access to these block devices, the Linux block cache will be in play. However, if you provide direct access, the answer to &lt;code&gt;will this work?&lt;/code&gt; would become less clear.&lt;/p&gt;

&lt;p&gt;Quoting from flashcache docs (  &lt;a href=&quot;https://github.com/facebook/flashcache/blob/master/doc/flashcache-sa-guide.txt&quot;&gt;flashcache - modes of caching&lt;/a&gt; ) , It provides 3 modes of caching: writeback, writethrough, and writearound. What happens when your SSD fails/disappears depends on your caching mode. Follow the above mentioned link for more info.&lt;/p&gt;

&lt;p&gt;During the initial stages of testing, we were handling a large number of writes per second - which resulted in periodic saturation of primary storage. We decided on using write-back caching mode (as the writes were very high) and the performance increase was significant. As our reads got higher, the performance went down, and now, I&amp;#39;m scratching my head to find a way to get around this.&lt;/p&gt;
</description>
        <pubDate>Mon, 04 Feb 2013 22:13:21 +0530</pubDate>
        <link>http://boopathi.in/blog/flashcache-blah-blah/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/flashcache-blah-blah/</guid>
        
        <category>flashcache</category>
        
        <category>system administration</category>
        
        
        <category>flashcache</category>
        
        <category>system administration</category>
        
      </item>
    
      <item>
        <title>Unhelpful JavaScript story: Are you new to JavaScript ?</title>
        <description>&lt;p&gt;Well, here goes a sophomoric short life story. A programmer who started developing his skills with C, C++ or any other imperative language, arriving at JavaScript could think that he has nothing to learn except the syntax and a few syntactic sugars the language&amp;#39;d provide. Well, like every movie, there has to be a not so ambiguous twist, and here we go - It&amp;#39;s definitely going to result in vain if that thought is his perseverance. In a contradiction, he might think this is a broad effort (quote: learning the language), but his goals are not to simply regurgitate the things he learnt, but to help boil down to what&amp;#39;s important to get him on his way. Coming to the next part of his JavaScript life, he would understand that, it&amp;#39;s merely a language which leaves out some of the basic structures and components that are so commonly used/needed. To reduce these boiler-plates and abstract browser inconsistencies, and to increase the level of tools/API, he would choose to use libraries which satisfy few/most of the requirements. He gets caught up in excitement and understands how easy development could be. And, it wouldn&amp;#39;t be anytime sooner, that he would understand, these libraries, some of them, don&amp;#39;t play well together. They overlap in functionality and features.&lt;/p&gt;

&lt;p&gt;Like there comes a time in every developer&amp;#39;s life where we arrive at some hypothesis of writing our own code for a library, he scrawls some code implementing some features. Before we continue, I would like to analyse his mistakes. May be he thought that his work&amp;#39;d be superior as he is eliminating most of the unnecessary stuff the library provides (or) may be he didn&amp;#39;t do enough research on what&amp;#39;s likely to be the most necessary thing in the application (or) may be there&amp;#39;s just this one small thing that isn&amp;#39;t quite right in the library, so he wants to rewrite it from scratch. The truth is, he has done it, I&amp;#39;ve done it, and you likely have too. The next phase of his life would be the annoying part. He realizes, but slowly, that he is doing nothing but what is so called as &amp;quot;re-inventing the wheel&amp;quot; and  whatever functionality he writes is already there under development for a significant amount of time, and the community that develops these things must have experienced something similar. He finds it funny that he wasn&amp;#39;t the only one who fell into this ludicrous life.&lt;/p&gt;

&lt;p&gt;Not a great scheme for an ending. I know. But some of you would&amp;#39;ve got the memo. :).&lt;/p&gt;

&lt;h2&gt;The advice section:&lt;/h2&gt;

&lt;p&gt;The long-evo idea about libraries is that these are developed in some remote part of the web and the community that develops these things is not available to approach by normal people. The idea, as certain as Heisenberg could be, is nothing but drivel.&lt;/p&gt;

&lt;p&gt;One thing that most of us don&amp;#39;t understand immediately is that, Learning JavaScript is not a one-time event. It&amp;#39;ll happen over a long period of time, but (with a little/more stress on this point) it&amp;#39;s important that you actually make it a priority to LEARN the language. Often people learn libraries, and not the language, a mistake which will certainly bite you in the end.&lt;/p&gt;

&lt;h2&gt;Blah blah stuff&lt;/h2&gt;

&lt;p&gt;Don&amp;#39;t get me wrong about writing your own libraries. It&amp;#39;s completely possible ;) .&lt;/p&gt;
</description>
        <pubDate>Fri, 23 Nov 2012 17:01:18 +0530</pubDate>
        <link>http://boopathi.in/blog/unhelpful-javascript-story-new-to-javascript/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/unhelpful-javascript-story-new-to-javascript/</guid>
        
        <category>javascript</category>
        
        <category>story</category>
        
        <category>unhelpful</category>
        
        
        <category>fact</category>
        
        <category>fun</category>
        
        <category>javascript</category>
        
        <category>lesson</category>
        
        <category>tips and tricks</category>
        
      </item>
    
      <item>
        <title>Threaded SSH</title>
        <description>&lt;blockquote&gt;
&lt;p&gt;Kindly note, this doesn&amp;#39;t mean implementation of threading in SSH.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Problem statement&lt;/h2&gt;

&lt;p&gt;When we have multiple servers to manage, we configure it in such a way that they are easily manageable. To meet this requirement, as a first thought, we make similarities in few of the configurations, packages and repositories used in/by those servers. This is mostly applicable in cases where/whenever High Availability, Sharing of resources and Horizontal Scaling comes into picture. Once everything is set, we might run into a situation, where we would want to run a script on all those servers and get the output and error  to one place for reviewing. Now, one way to do this is, while setting up those servers, we could use a tool, called MCollective, that pertains for these kinds of operations. The quick and dirty way is to ssh into every server, write the script, create a cron job that invokes this script, and throw the output to some static page that can be fetched over HTTP. Now, being a system administrator, we would &lt;strong&gt;NOT&lt;/strong&gt; want to do that. We would end up writing a tiny script in bash, which sends the command over ssh, executes it, and standard output is redirected to the system(callee). We have to find a better way (and a Simple way) to do this.&lt;/p&gt;

&lt;h2&gt;Sequential SSH&lt;/h2&gt;

&lt;p&gt;As discussed above, whenever we would like to execute something over SSH, we write something like this.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..50&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        ssh boopathi@server-&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;@myhost.com &lt;span class=&quot;s2&quot;&gt;&amp;quot;top -b -n1 | head -n5&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code, sequentially, after getting authorized, executes the command within quotes (the top 5 processes in that system), and echoes the output to the callee. This takes lots of time where the callee waits until the previous instance has exited.&lt;/p&gt;

&lt;h2&gt;Threaded SSH (Solution)&lt;/h2&gt;

&lt;p&gt;Threading seems to solve the issue of waiting for every instance to be completed. So, one of the possible SIMPLE solutions, would be to invoke the ssh function in separate threads. As, each of the thread spawned is further going to invoke a sub-process that runs SSH, and also, as there is nothing to be shared between these instances, we can safely write a SIMPLE module that would facilitate this feature. So, now, all connections are instantiated in parallel or whenever a new thread can be spawned. The output is thrown to STDOUT of the callee whenever a thread exits. And it obviously becomes much faster on a multi-core system.&lt;/p&gt;

&lt;h2&gt;Code (Python)&lt;/h2&gt;

&lt;p&gt;You could as well follow this gist, where the revisions are maintained.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/4046754&quot;&gt;https://gist.github.com/4046754&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Code:&lt;/h3&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;c&quot;&gt;#!/usr/bin/python&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# This doesn&amp;#39;t mean threading in ssh. What it means is, every thread&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# that this program spawns, creates a new subprocess to perform the&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# system &amp;quot;ssh&amp;quot; command.&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# Sample Usages&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# =============&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# 1.&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# for i in server1 server2 server3 server4;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# do echo username@$i;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# done | ./tssh &amp;quot;echo &amp;#39;Good night :P&amp;#39;; rm -rf /; &amp;quot;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# 2.&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# cat connection_list | ./tssh &amp;quot;ifconfig lo&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# 3.&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# cat server_list | while read server;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# do echo &amp;quot;username@$server&amp;quot;;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# done | ./tssh &amp;quot;top -b -n1 | head -n10&amp;quot; --noheader&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;shlex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;subprocess&lt;/span&gt;


    &lt;span class=&quot;n&quot;&gt;basecommand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;ssh -o StrictHostKeyChecking=no&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;echo &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; says,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;; echo &amp;#39;==========================================&amp;#39;; &amp;quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;nohead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;--noheader&amp;#39;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Runner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Runner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shlex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basecommand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nohead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;sout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Popen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PIPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39; __main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;raw_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;ne&quot;&gt;EOFError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Runner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;echo &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt; Internals&lt;/h2&gt;

&lt;p&gt;The code reads from STDIN (Standard Input) - the list of servers, till EOF (End of File). Once this collection is made, it spawns a thread(for every server), which constructs a sub-process that runs the SSH command. The --noheader  flag is just to prevent pretty print option. Use it if you&amp;#39;ve to parse the output or use it on another process.&lt;/p&gt;

&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;No big deal. Save the source. Give execute permissions. Those who are struggling to install, use this script to download and install.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;    curl https://raw.github.com/gist/4046754/af7b26f723c9da37a9e34102be93285ed92be756/tssh.py &amp;gt; /usr/bin/tssh &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chmod +x /usr/bin/tssh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        <pubDate>Thu, 22 Nov 2012 00:28:02 +0530</pubDate>
        <link>http://boopathi.in/blog/threaded-ssh/</link>
        <guid isPermaLink="true">http://boopathi.in/blog/threaded-ssh/</guid>
        
        <category>multiple server ssh</category>
        
        <category>ssh</category>
        
        <category>system administration</category>
        
        <category>threaded ssh</category>
        
        
        <category>ssh</category>
        
        <category>system administration</category>
        
        <category>threading</category>
        
      </item>
    
  </channel>
</rss>
