<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

  <title><![CDATA[Kevin van Zonneveld]]></title>
  
  <link href="http://kvz.io/" />
  <updated>2013-05-08T14:29:10+02:00</updated>
  <id>http://kvz.io/</id>
  <author>
    <name><![CDATA[Kevin van Zonneveld]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/kvz" /><feedburner:info uri="kvz" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/3.0/" /><feedburner:emailServiceId>kvz</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry>
    <title type="html"><![CDATA[Loosely Typed Code Deserves Triple Equality]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/c5gwDTIDdDM/" />
    <updated>2013-04-23T10:18:00+02:00</updated>
    <id>http://kvz.io/blog/2013/04/23/change-your-codebase-to-use-triple-equality</id>
    <content type="html">&lt;p&gt;In loosely typed languages such as JavaScript or PHP, using &lt;code&gt;==&lt;/code&gt;
to compare values is bad practice because it doesn&amp;#8217;t
account for type, hence &lt;code&gt;false == 0 == '' == null == undefined&lt;/code&gt;, etc.
And you may accidentally match more than you bargained for.&lt;/p&gt;

&lt;p&gt;If you want you can limit unintented effects &amp;amp; bugs this may lead to,
it&amp;#8217;s often wise to use &lt;code&gt;===&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the process of converting legacy
codebases to use these triple equality operators, I find that as a rule
of thumb you can almost &lt;strong&gt;always force triple equality&lt;/strong&gt; in case of
comparing variables against &lt;strong&gt;non-numerical strings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s just never a case where you want the text &lt;code&gt;'Kevin'&lt;/code&gt;
to pass for the boolean &lt;code&gt;true&lt;/code&gt;, or the number &lt;code&gt;3&lt;/code&gt;.
And if that can still happen in your legacy codebase,
you&amp;#8217;ll want to limit those risks rather sooner than later. Even if that
breaks things that now accidentally, work.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;Switching legacy code that compares against numerical strings, numbers, or
booleans is trickier.
For instance user input often arrives as a string, so
bluntly changing &lt;code&gt;age == 4&lt;/code&gt; to &lt;code&gt;age === 4&lt;/code&gt;, will now no longer match the user input &lt;code&gt;age&lt;/code&gt;,
and introduce more problems than it solves. Addressing these cases needs more thought &amp;amp; care.&lt;/p&gt;

&lt;p&gt;To change all of the text-compare cases, here&amp;#8217;s a regex that can, to a degree, automate
this otherwise much more painful process.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;([&lt;/span&gt;0-9a-zA-Z&lt;span class="se"&gt;\_&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;+&lt;span class="o"&gt;[&lt;/span&gt;!&lt;span class="o"&gt;=])=(&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;+&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;^0-9&lt;span class="se"&gt;\-\.&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You could use this in a programs like Vim or &lt;a href="http://www.araxis.com/replace-in-files/index-eur.html"&gt;Araxis&lt;/a&gt;,
or escape it and then use it in &lt;code&gt;sed&lt;/code&gt;. Make sure the changes are under source control and reviewed &amp;amp; tested
before committed &amp;amp; pushed.&lt;/p&gt;

&lt;p&gt;I tested this on legacy JavaScript and PHP projects. Here you can see the potential
&lt;a href="https://github.com/kvz/phpjs/commit/d60549d5ec65f1ca63acb33a534616d58f47a4c4"&gt;issues caught in php.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Improvements welcome.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/c5gwDTIDdDM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/04/23/change-your-codebase-to-use-triple-equality/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Scrape All Text from a Domain]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/52OZXMQgY0U/" />
    <updated>2013-04-19T11:32:00+02:00</updated>
    <id>http://kvz.io/blog/2013/04/19/obtain-all-text-from-your-website</id>
    <content type="html">&lt;p&gt;Here are some commands to download the most important pages of your
site as plain text (determined by &lt;code&gt;MAX_DEPTH&lt;/code&gt;), and save it into one
big &lt;code&gt;&amp;lt;DOMAIN&amp;gt;.txt&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;This could come in handy when you want to have everything checked for
grammar &amp;amp; spelling errors.&lt;/p&gt;

&lt;p&gt;After the spellcheck you&amp;#8217;d still have to search through your
codebase / database to find &amp;amp; fix the culprits, but this should already save
you some time in discovery.&lt;/p&gt;

&lt;!-- more --&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt; (obtain_site_text.sh)&lt;/span&gt; &lt;a href='http://kvz.io/downloads/code/obtain_site_text.sh'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#!/usr/bin/env bash -e&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Downloads a site&amp;#39;s text to 1 text file, so you can easily&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# have it grammer/spellchecked&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Requires: wget, html2text&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Recommened: pandoc vs html2text&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Improve at: http://kvz.io/blog/2013/04/19/obtain-all-text-from-your-website/&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${DOMAIN}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Cannot continue without DOMAIN. &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${EXCLUDE}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;EXCLUDE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*.css,*.js,*.rss,*.xml,*.png,*.jpg,*.jpeg,*.gif,*.flv,*.swf,*.mp4,*.mov,*.mp3,*.wav&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${MAX_DEPTH}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;MAX_DEPTH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${OUTPUT}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;OUTPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;./${DOMAIN}.txt&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${TMPDIR}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;TMPDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/tmp&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${TXTENGINE}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -x &lt;span class="s2"&gt;&amp;quot;$(which pandoc)&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;TXTENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pandoc +RTS -K16m -RTS -t markdown -o- -f html -i&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${TXTENGINE}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -x &lt;span class="s2"&gt;&amp;quot;$(which html2text)&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;TXTENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;html2text -nobs&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${TXTENGINE}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Cannot continue without pandoc or html2text. &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;wget &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --adjust-extension &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --convert-links &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --directory-prefix&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${TMPDIR}&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --level&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${MAX_DEPTH}&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --no-parent &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --recursive &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --reject&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${EXCLUDE}&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --restrict-file-names&lt;span class="o"&gt;=&lt;/span&gt;windows,lowercase &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s2"&gt;&amp;quot;http://${DOMAIN}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;&amp;quot;${OUTPUT}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -f &lt;span class="s2"&gt;&amp;quot;${OUTPUT}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find &lt;span class="s2"&gt;&amp;quot;${TMPDIR}/${DOMAIN}&amp;quot;&lt;/span&gt; -type f -print0 -name &lt;span class="s1"&gt;&amp;#39;*.html&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  |while &lt;span class="nb"&gt;read&lt;/span&gt; -d &lt;span class="s1"&gt;$&amp;#39;\0&amp;#39;&lt;/span&gt; file; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;imported by ${0} from: $(echo &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; |sed &amp;quot;&lt;/span&gt;s@^&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TMPDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DOMAIN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@@&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class="s2"&gt;&amp;quot;${OUTPUT}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;==================================&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class="s2"&gt;&amp;quot;${OUTPUT}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TXTENGINE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${file}&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class="s2"&gt;&amp;quot;${OUTPUT}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;\n\n\n\n&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class="s2"&gt;&amp;quot;${OUTPUT}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; Combined text file ready in ${OUTPUT}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; To cleanup after this script, type: rm -rf \&amp;quot;${TMPDIR}/${DOMAIN}\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Required:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install wget html2text &lt;span class="c"&gt;# or apt-get install wget html2text&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Run it:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;kvz.io ./obtain_site_text.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Recommended:&lt;/p&gt;

&lt;p&gt;If you can install &lt;a href="http://johnmacfarlane.net/pandoc/README.html"&gt;Pandoc&lt;/a&gt;,
the resulting text output will be in Markdown and of much higher quality.&lt;/p&gt;

&lt;p&gt;Improvements are more than welcome!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/52OZXMQgY0U" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/04/19/obtain-all-text-from-your-website/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Migrate Redis Keys Without RDB Files]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/KdE2UO84AHg/" />
    <updated>2013-04-16T15:28:00+02:00</updated>
    <id>http://kvz.io/blog/2013/04/16/migrate-redis-data-without-filesystem-access</id>
    <content type="html">&lt;p&gt;Recently we moved the &lt;a href="http://status.transloadit.com"&gt;Transloadit status page&lt;/a&gt;
from an unmanaged EC2 instance to the Nodejitsu platform.
We kept status uptime history in redis, and obviously I wanted to preserve that
data.&lt;/p&gt;

&lt;p&gt;For the new setup I did not have access to the filesystem, I only had a redis
port to talk to. So instead of rsyncing the &lt;code&gt;.rdb&lt;/code&gt; file I used rync replication
to migrate the data between instances.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;Here&amp;#8217;s the redacted terminal transcript, the sending host is
old-redis.transloadit.com, the receiving host is new-redis.transloadit.com.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# First let&amp;#39;s connect to the new host&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;redis-cli -h new-redis.transloadit.com
&lt;/span&gt;&lt;span class='line'&gt;redis new-redis.transloadit.com:6379&amp;gt; AUTH ...:...
&lt;/span&gt;&lt;span class='line'&gt;OK
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Let&amp;#39;s start with a clean slate, first make sure it stands alone&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;redis new-redis.transloadit.com:6379&amp;gt; SLAVEOF NO ONE
&lt;/span&gt;&lt;span class='line'&gt;OK
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# WARNING! This will trash all existing data on the receiving host&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;redis new-redis.transloadit.com:6379&amp;gt; FLUSHALL
&lt;/span&gt;&lt;span class='line'&gt;OK
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Now setup replication so that redis copies all keys from old to new&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;redis new-redis.transloadit.com:6379&amp;gt; SLAVEOF old-redis.transloadit.com 6379
&lt;/span&gt;&lt;span class='line'&gt;OK
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Wait until INFO shows `role:slave`, and the&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# same amount of keys as on the old server.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;redis new-redis.transloadit.com:6379&amp;gt; INFO
&lt;/span&gt;&lt;span class='line'&gt;...
&lt;/span&gt;&lt;span class='line'&gt;role:slave
&lt;/span&gt;&lt;span class='line'&gt;...
&lt;/span&gt;&lt;span class='line'&gt;OK
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Check some random keys to see if you have all the data.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;redis new-redis.transloadit.com:6379&amp;gt; LRANGE &lt;span class="nb"&gt;history &lt;/span&gt;0 1
&lt;/span&gt;&lt;span class='line'&gt; 1&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;{\&amp;quot;message\&amp;quot;:\&amp;quot;All services operational\&amp;quot;,\&amp;quot;date\&amp;quot;:\&amp;quot;2013-04-15\&amp;quot;}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;OK
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Looks good, now let&amp;#39;s disable slave mode, make it stand alone again&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;redis new-redis.transloadit.com:6379&amp;gt; SLAVEOF NO ONE
&lt;/span&gt;&lt;span class='line'&gt;OK
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And that&amp;#8217;s it, you&amp;#8217;ve copied all the redis keys without using &lt;code&gt;.rdb&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Hope this helps, let me know if you have suggestions.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/KdE2UO84AHg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/04/16/migrate-redis-data-without-filesystem-access/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Let's Make DNS Outage Suck Less]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/adNHeaW9Ce0/" />
    <updated>2013-03-27T14:56:00+01:00</updated>
    <id>http://kvz.io/blog/2013/03/27/poormans-way-to-decent-dns-failover</id>
    <content type="html">&lt;p&gt;&lt;em&gt;This article was featured on the Hacker News frontpage. Feel free to &lt;a href="https://news.ycombinator.com/item?id=5450140"&gt;checkout comments there&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately the Linux DNS resolver has no direct support for detecting and doing failovers for DNS servers. It keeps feeding requests to your primary resolving nameserver, waits for a configured timeout, attempts again, and only then tries the second nameserver.&lt;/p&gt;

&lt;p&gt;This typically means nearly 30s delay for all request as long as your primary nameserver is unreachable. It doesn&amp;#8217;t learn to directly target your secondary nameserver so long as there is trouble.&lt;/p&gt;

&lt;p&gt;Even with the most optimal configuration, the delay will still be measured in seconds per request. For many requests, that&amp;#8217;s many more seconds.&lt;/p&gt;

&lt;p&gt;I wanted to solve this.&lt;/p&gt;

&lt;!--more--&gt;


&lt;p&gt;Mainly because over at &lt;a href="http://transloadit.com"&gt;Transloadit&lt;/a&gt; our Amazon EC2 resolving nameserver (&lt;code&gt;172.16.0.23&lt;/code&gt;) is unreachable too often.
When it happens it causes big delays and queues in some processes and even downtime as we rely on domain-&gt;ip translation. For instance customer could tell us to download 1000 images from different urls, watermark them, upload them to an sFTP server.&lt;/p&gt;

&lt;p&gt;I wanted solid failover to Google / Level3&amp;#8217;s nameservers in case Amazon&amp;#8217;s went down again. And then failback as soon as possible, because Amazon can resolve &lt;code&gt;server33.transloadit.com&lt;/code&gt; hostnames to LAN IPs where applicable, resulting in lower latency for instance-to-instance communication, when encoding machines need to work together.&lt;/p&gt;

&lt;!-- I know that Spotify actually uses [DNS as a distributed datastore](http://labs.spotify.com/2013/02/25/in-praise-of-boring-technology/) for service discovery &amp; configuration management.
 --&gt;


&lt;p&gt;But whatever the usecase, there&amp;#8217;s a need for better way to failover.&lt;/p&gt;

&lt;p&gt;Ideally one that does not involve more local proxy daemons, external services, keepalived VRRP IPs, etc. as that would just introduce more complexity and Single Point Of Failures.
It should be transparent, archaic and at most rely on &lt;code&gt;crontab&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I wrote &lt;a href="https://github.com/kvz/nsfailover"&gt;nsfailover&lt;/a&gt; in bash, and have it
replace the resolve-configuration when needed. It&amp;#8217;s rugged, easy to debug, hard to break, and has been working really well for us so far.&lt;/p&gt;

&lt;p&gt;Running it is pretty simple, too. Configuration such as &lt;code&gt;NS_1&lt;/code&gt;
is done via environment variables, here&amp;#8217;s an example where I set
it globally using export:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ubuntu@abril:/srv/current$ export NS_1=172.16.0.23
ubuntu@abril:/srv/current$ sudo nsfailover.sh
2013-03-27 14:18:22 UTC [     info] Best nameserver is primary (172.16.0.23)
2013-03-27 14:18:22 UTC [     info] No need to change /etc/resolv.conf
ubuntu@abril:/srv/current$
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or maybe you want also want to define the backup nameserver (defaults
to Google&amp;#8217;s), and just pass the config to this process:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ubuntu@abril:/srv/current$ NS_1=8.8.8.8 NS_2=8.8.4.4 sudo -E nsfailover.sh
2013-03-27 15:01:53 UTC [     info] Best nameserver is primary (8.8.8.8)

 # Written by /srv/current/stack/bin/nsfailover.sh @ 20130327150153
 nameserver 8.8.8.8
 options timeout:3 attempts:1
 search compute-1.internal

2013-03-27 15:01:53 UTC [emergency] I changed /etc/resolv.conf to primary (8.8.8.8)
ubuntu@abril:/srv/current$
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Tight!&lt;/p&gt;

&lt;p&gt;Now if you save this in &lt;a href="http://kvz.io/blog/2012/12/31/lock-your-cronjobs/"&gt;crontab with a timeout&lt;/a&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;crontab -e
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# By default, NS_2 is Google, NS_3 is Level3, so only your NS_1 is required:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;* * * * * timeout -s9 50s &lt;span class="nv"&gt;NS_1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;172.16.0.23 nsfailover.sh 2&amp;gt;&amp;amp;1 |logger -t cron-nsfailover
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;it turns out, Bob indeed is your uncle : )&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;logger&lt;/code&gt; pipe will make all output go to syslog so to get notified when a
failover happens, just scan for &lt;code&gt;[emergency]&lt;/code&gt; in the &lt;code&gt;cron-nsfailover&lt;/code&gt; tag.
In our case, Papertrail receives our syslog and I made it report to Campfire when this happens.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s more documentation &lt;a href="https://github.com/kvz/nsfailover"&gt;available on Github&lt;/a&gt;.
Let me know if you have any improvements or send me a pull request : )&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/adNHeaW9Ce0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/03/27/poormans-way-to-decent-dns-failover/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Find duplicate input with MySQL]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/dTDL_bdq7Pk/" />
    <updated>2013-03-04T11:32:00+01:00</updated>
    <id>http://kvz.io/blog/2013/03/04/find-duplicate-input-with-mysql</id>
    <content type="html">&lt;p&gt;Back to basic, let&amp;#8217;s brush up on some &lt;code&gt;SQL&lt;/code&gt; : )&lt;/p&gt;

&lt;p&gt;At my company we have employees creating customer accounts every day.
Sometimes we make mistakes, for instance, we forget to check if the
company already was a customer (maybe 10y ago they may have had a product).&lt;/p&gt;

&lt;p&gt;Duplicate accounts can cause all sorts of problems, so I wanted
way to detect them with &lt;code&gt;SQL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The problem was, the company names may have been entered with
different punctuation, whitespace,
etc. So I needed similar names to surface from the depths of our database,
not just exact matches (that would have been too easy : )&lt;/p&gt;

&lt;!-- More --&gt;


&lt;p&gt;For the solution I turned to &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_soundex"&gt;SOUNDEX&lt;/a&gt;
for fuzzy matching similar sounding company names, and then
review the results myself (false positives are possible, but since they would be few,
it becomes a simple task to doublecheck) and report back to our company.&lt;/p&gt;

&lt;p&gt;I thought I&amp;#8217;d share&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;partly because it could be useful to others
(obviously this could be used to detect all kinds of user generated typos and similar
entries);&lt;/li&gt;
&lt;li&gt;mostly because I&amp;#8217;m curious to find if there is a better (more performant)
way to write this query.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Do you know how? Leave a comment : )&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sql'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;-- Select all the individual company names that have a&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;-- soundex_code that occurs more than once (I now use a subquery for that)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;SOUNDEX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;soundex_code&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;SOUNDEX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;-- Subquery: select all soundex_codes that occur more than once,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;-- (this does not return the individual company names that share them)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;SOUNDEX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;soundex_code&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c1"&gt;-- More specific criteria to define who you want to compare&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;soundex_code&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;HAVING&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;soundex_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This e.g. returns:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="sb"&gt;`&lt;/span&gt;id&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;customer_name&lt;span class="sb"&gt;`&lt;/span&gt;  &lt;span class="sb"&gt;`&lt;/span&gt;soundex_code&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt; 291  F.S. Hosting     F2352
&lt;/span&gt;&lt;span class='line'&gt; 1509 FS hosting       F2352
&lt;/span&gt;&lt;span class='line'&gt; 9331 R  Schmit        R253
&lt;/span&gt;&lt;span class='line'&gt; 9332 R Schmit         R253
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;By the way: The SQL is formatted according to my old &lt;a href="http://kvz.io/blog/2009/03/04/sql-formatting/"&gt;SQL Formatting blogpost&lt;/a&gt;.
Exactly 4 years after I published it, I still find it a pretty useful code convention.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/dTDL_bdq7Pk" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/03/04/find-duplicate-input-with-mysql/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Introducing BASH3 Boilerplate]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/1am-RnlR2eE/" />
    <updated>2013-02-26T00:19:00+01:00</updated>
    <id>http://kvz.io/blog/2013/02/26/introducing-bash3boilerplate</id>
    <content type="html">&lt;p&gt;There are many cases where using BASH to code ends up
overcomplicating things, but due to it&amp;#8217;s portability
there are many cases that make it the best tool for the job.&lt;/p&gt;

&lt;p&gt;When I do hack on BASH scripts, I often find there are things like
logging, configuration, commandline argument
parsing that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I need everytime&lt;/li&gt;
&lt;li&gt;Take quite some effort to get right, and&lt;/li&gt;
&lt;li&gt;Keep you from your actual work.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here&amp;#8217;s an attempt at bundling those things in a generalized way so that
they are reusable as-is in most of my (and hopefully your) programs.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h2&gt;Goals&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m going to be pragmatic and be violating some good practices like DRY
and the things I know about sourcing, submodules,
package management, etc.&lt;/p&gt;

&lt;p&gt;I feel that when a program consists of multiple files, BASH
may very well not be the right tool for the job.&lt;/p&gt;

&lt;p&gt;I propose people copy-paste &lt;code&gt;main.sh&lt;/code&gt;, then delete the
parts they don&amp;#8217;t need, and write the rest of their script
below &lt;code&gt;### Runtime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Copy-pasting and removing what you don&amp;#8217;t need may not seem
very rocket-scientific or 2013, but in fact, neither is BASH.&lt;/p&gt;

&lt;p&gt;Keeping things simple, small and lightweight should be key
here.&lt;/p&gt;

&lt;p&gt;Aiming for portability, I&amp;#8217;m targetting BASH 3 (OSX still ships
with 3 for instance). If you&amp;#8217;re going to ask people to install
BASH 4 first, you might as well pick a more advanced language as a
dependency.&lt;/p&gt;

&lt;p&gt;The main template should only have features that are needed
80% of the time you write BASH.&lt;/p&gt;

&lt;p&gt;Other cool functions can be adopted by the repository,
but should not be referenced by the &lt;code&gt;main.sh&lt;/code&gt; template and function
purely as a resource.&lt;/p&gt;

&lt;h2&gt;Features&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Structure&lt;/li&gt;
&lt;li&gt;Configuration by environment variables&lt;/li&gt;
&lt;li&gt;Configuration by commandline arguments (definitions parsed from help info,
so no duplication needed)&lt;/li&gt;
&lt;li&gt;Magic variables like &lt;code&gt;__FILE__&lt;/code&gt; and &lt;code&gt;__DIR__&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Logging that supports colors and is compatible with &lt;a href="http://en.wikipedia.org/wiki/Syslog#Severity_levels"&gt;Syslog Severity levels&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Conventions / Recommendations&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It&amp;#8217;s the task of the script&amp;#8217;s &lt;strong&gt;caller&lt;/strong&gt; to: Redirect the output to appropriate locations&lt;/li&gt;
&lt;li&gt;It&amp;#8217;s the task of the script&amp;#8217;s &lt;strong&gt;caller&lt;/strong&gt; to: Correctly set the &lt;code&gt;PATH&lt;/code&gt; variable (think &lt;a href="http://kvz.io/blog/2007/07/29/schedule-tasks-on-linux-using-crontab/"&gt;cronjobs&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Use spaces vs tabs so you can copy-paste parts directly into
the console, without BASH&amp;#8217;s automcomplete firing on every tab
character&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;set -eu&lt;/code&gt;, so it will break on every error
and undefined variable. If you&amp;#8217;re expecting an error, add &lt;code&gt;||true&lt;/code&gt;
to your command. &lt;code&gt;set -eu&lt;/code&gt; is better that relying on &lt;code&gt;#!/bin/bash -eu&lt;/code&gt;, that will be ignored
when sourced or executed like &lt;code&gt;bash main.sh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Checkout &lt;a href="http://www.masterzen.fr/2013/01/13/the-10-commandments-of-logging/"&gt;The 10 Commandments of Logging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Adhere Syslog. Sure, skip &lt;code&gt;notice&lt;/code&gt;, &lt;code&gt;alert&lt;/code&gt;, &lt;code&gt;critical&lt;/code&gt;, if you need just 3
levels. You should still crash in &lt;code&gt;emergency&lt;/code&gt;, debug in &lt;code&gt;debug&lt;/code&gt;, inform in &lt;code&gt;info&lt;/code&gt;.
The world has had plenty smart folks creating new cool logstandards, dealing with them does not
make life easier though.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Code&lt;/h2&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt; (main.sh)&lt;/span&gt; &lt;a href='http://kvz.io/downloads/code/bash3boilerplate/main.sh'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;span class='line-number'&gt;54&lt;/span&gt;
&lt;span class='line-number'&gt;55&lt;/span&gt;
&lt;span class='line-number'&gt;56&lt;/span&gt;
&lt;span class='line-number'&gt;57&lt;/span&gt;
&lt;span class='line-number'&gt;58&lt;/span&gt;
&lt;span class='line-number'&gt;59&lt;/span&gt;
&lt;span class='line-number'&gt;60&lt;/span&gt;
&lt;span class='line-number'&gt;61&lt;/span&gt;
&lt;span class='line-number'&gt;62&lt;/span&gt;
&lt;span class='line-number'&gt;63&lt;/span&gt;
&lt;span class='line-number'&gt;64&lt;/span&gt;
&lt;span class='line-number'&gt;65&lt;/span&gt;
&lt;span class='line-number'&gt;66&lt;/span&gt;
&lt;span class='line-number'&gt;67&lt;/span&gt;
&lt;span class='line-number'&gt;68&lt;/span&gt;
&lt;span class='line-number'&gt;69&lt;/span&gt;
&lt;span class='line-number'&gt;70&lt;/span&gt;
&lt;span class='line-number'&gt;71&lt;/span&gt;
&lt;span class='line-number'&gt;72&lt;/span&gt;
&lt;span class='line-number'&gt;73&lt;/span&gt;
&lt;span class='line-number'&gt;74&lt;/span&gt;
&lt;span class='line-number'&gt;75&lt;/span&gt;
&lt;span class='line-number'&gt;76&lt;/span&gt;
&lt;span class='line-number'&gt;77&lt;/span&gt;
&lt;span class='line-number'&gt;78&lt;/span&gt;
&lt;span class='line-number'&gt;79&lt;/span&gt;
&lt;span class='line-number'&gt;80&lt;/span&gt;
&lt;span class='line-number'&gt;81&lt;/span&gt;
&lt;span class='line-number'&gt;82&lt;/span&gt;
&lt;span class='line-number'&gt;83&lt;/span&gt;
&lt;span class='line-number'&gt;84&lt;/span&gt;
&lt;span class='line-number'&gt;85&lt;/span&gt;
&lt;span class='line-number'&gt;86&lt;/span&gt;
&lt;span class='line-number'&gt;87&lt;/span&gt;
&lt;span class='line-number'&gt;88&lt;/span&gt;
&lt;span class='line-number'&gt;89&lt;/span&gt;
&lt;span class='line-number'&gt;90&lt;/span&gt;
&lt;span class='line-number'&gt;91&lt;/span&gt;
&lt;span class='line-number'&gt;92&lt;/span&gt;
&lt;span class='line-number'&gt;93&lt;/span&gt;
&lt;span class='line-number'&gt;94&lt;/span&gt;
&lt;span class='line-number'&gt;95&lt;/span&gt;
&lt;span class='line-number'&gt;96&lt;/span&gt;
&lt;span class='line-number'&gt;97&lt;/span&gt;
&lt;span class='line-number'&gt;98&lt;/span&gt;
&lt;span class='line-number'&gt;99&lt;/span&gt;
&lt;span class='line-number'&gt;100&lt;/span&gt;
&lt;span class='line-number'&gt;101&lt;/span&gt;
&lt;span class='line-number'&gt;102&lt;/span&gt;
&lt;span class='line-number'&gt;103&lt;/span&gt;
&lt;span class='line-number'&gt;104&lt;/span&gt;
&lt;span class='line-number'&gt;105&lt;/span&gt;
&lt;span class='line-number'&gt;106&lt;/span&gt;
&lt;span class='line-number'&gt;107&lt;/span&gt;
&lt;span class='line-number'&gt;108&lt;/span&gt;
&lt;span class='line-number'&gt;109&lt;/span&gt;
&lt;span class='line-number'&gt;110&lt;/span&gt;
&lt;span class='line-number'&gt;111&lt;/span&gt;
&lt;span class='line-number'&gt;112&lt;/span&gt;
&lt;span class='line-number'&gt;113&lt;/span&gt;
&lt;span class='line-number'&gt;114&lt;/span&gt;
&lt;span class='line-number'&gt;115&lt;/span&gt;
&lt;span class='line-number'&gt;116&lt;/span&gt;
&lt;span class='line-number'&gt;117&lt;/span&gt;
&lt;span class='line-number'&gt;118&lt;/span&gt;
&lt;span class='line-number'&gt;119&lt;/span&gt;
&lt;span class='line-number'&gt;120&lt;/span&gt;
&lt;span class='line-number'&gt;121&lt;/span&gt;
&lt;span class='line-number'&gt;122&lt;/span&gt;
&lt;span class='line-number'&gt;123&lt;/span&gt;
&lt;span class='line-number'&gt;124&lt;/span&gt;
&lt;span class='line-number'&gt;125&lt;/span&gt;
&lt;span class='line-number'&gt;126&lt;/span&gt;
&lt;span class='line-number'&gt;127&lt;/span&gt;
&lt;span class='line-number'&gt;128&lt;/span&gt;
&lt;span class='line-number'&gt;129&lt;/span&gt;
&lt;span class='line-number'&gt;130&lt;/span&gt;
&lt;span class='line-number'&gt;131&lt;/span&gt;
&lt;span class='line-number'&gt;132&lt;/span&gt;
&lt;span class='line-number'&gt;133&lt;/span&gt;
&lt;span class='line-number'&gt;134&lt;/span&gt;
&lt;span class='line-number'&gt;135&lt;/span&gt;
&lt;span class='line-number'&gt;136&lt;/span&gt;
&lt;span class='line-number'&gt;137&lt;/span&gt;
&lt;span class='line-number'&gt;138&lt;/span&gt;
&lt;span class='line-number'&gt;139&lt;/span&gt;
&lt;span class='line-number'&gt;140&lt;/span&gt;
&lt;span class='line-number'&gt;141&lt;/span&gt;
&lt;span class='line-number'&gt;142&lt;/span&gt;
&lt;span class='line-number'&gt;143&lt;/span&gt;
&lt;span class='line-number'&gt;144&lt;/span&gt;
&lt;span class='line-number'&gt;145&lt;/span&gt;
&lt;span class='line-number'&gt;146&lt;/span&gt;
&lt;span class='line-number'&gt;147&lt;/span&gt;
&lt;span class='line-number'&gt;148&lt;/span&gt;
&lt;span class='line-number'&gt;149&lt;/span&gt;
&lt;span class='line-number'&gt;150&lt;/span&gt;
&lt;span class='line-number'&gt;151&lt;/span&gt;
&lt;span class='line-number'&gt;152&lt;/span&gt;
&lt;span class='line-number'&gt;153&lt;/span&gt;
&lt;span class='line-number'&gt;154&lt;/span&gt;
&lt;span class='line-number'&gt;155&lt;/span&gt;
&lt;span class='line-number'&gt;156&lt;/span&gt;
&lt;span class='line-number'&gt;157&lt;/span&gt;
&lt;span class='line-number'&gt;158&lt;/span&gt;
&lt;span class='line-number'&gt;159&lt;/span&gt;
&lt;span class='line-number'&gt;160&lt;/span&gt;
&lt;span class='line-number'&gt;161&lt;/span&gt;
&lt;span class='line-number'&gt;162&lt;/span&gt;
&lt;span class='line-number'&gt;163&lt;/span&gt;
&lt;span class='line-number'&gt;164&lt;/span&gt;
&lt;span class='line-number'&gt;165&lt;/span&gt;
&lt;span class='line-number'&gt;166&lt;/span&gt;
&lt;span class='line-number'&gt;167&lt;/span&gt;
&lt;span class='line-number'&gt;168&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Template to write better bash scripts. More info: http://kvz.io&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Version 0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Usage:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#  LOG_LEVEL=7 ./template.sh first_arg second_arg&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Licensed under MIT&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Copyright (c) 2013 Kevin van Zonneveld&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# http://twitter.com/kvz&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;### Configuration&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#####################################################################&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Environment variables&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;6&amp;quot;&lt;/span&gt; &lt;span class="c"&gt;# 7 = debug -&amp;gt; 0 = emergency&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Commandline options. This defines the usage page, and is used to parse cli opts &amp;amp; defaults from.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# the parsing is unforgiving so be precise in your syntax:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r -d &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; usage &lt;span class="s"&gt;&amp;lt;&amp;lt;-&amp;#39;EOF&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  -f   [arg] Filename to process.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  -t   [arg] Location of tempfile. Default=&amp;quot;/tmp/x&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  -d         Enables debug mode&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  -h         This page&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Set magic variables for current FILE &amp;amp; DIR&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;__FILE__&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(test -L &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;amp;&amp;amp; readlink &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; || echo &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;__DIR__&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(cd &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dirname &lt;span class="s2"&gt;&amp;quot;${__FILE__}&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;; echo $(pwd);)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;### Functions&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#####################################################################&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;_fmt &lt;span class="o"&gt;()&lt;/span&gt;      &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;color_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\x1b[32m&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;color_bad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\x1b[31m&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${color_bad}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;debug&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;info&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;notice&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${color_ok}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;color_reset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\x1b[0m&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${TERM}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;xterm&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -t 1 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c"&gt;# Don&amp;#39;t use colors on pipes or non-recognized terminals&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;color_reset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;$(date -u +&amp;quot;&lt;/span&gt;%Y-%m-%d %H:%M:%S UTC&lt;span class="s2"&gt;&amp;quot;) ${color}$(printf &amp;quot;&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;%9s&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; ${1})${color_reset}&amp;quot;&lt;/span&gt;;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;emergency &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt emergency) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="nb"&gt;exit &lt;/span&gt;1; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;alert &lt;span class="o"&gt;()&lt;/span&gt;     &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; -ge 1 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt alert) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;critical &lt;span class="o"&gt;()&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; -ge 2 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt critical) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;error &lt;span class="o"&gt;()&lt;/span&gt;     &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; -ge 3 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt error) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;warning &lt;span class="o"&gt;()&lt;/span&gt;   &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; -ge 4 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt warning) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;notice &lt;span class="o"&gt;()&lt;/span&gt;    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; -ge 5 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt notice) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;info &lt;span class="o"&gt;()&lt;/span&gt;      &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; -ge 6 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt info) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;debug &lt;span class="o"&gt;()&lt;/span&gt;     &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; -ge 7 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(_fmt debug) ${@}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;&lt;span class="nb"&gt;help&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; ${@}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;  ${usage}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;cleanup_before_exit &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  info &lt;span class="s2"&gt;&amp;quot;Cleaning up. Done&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup_before_exit EXIT
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;### Parse commandline options&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#####################################################################&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Translate usage string -&amp;gt; getopts arguments, and set $arg_&amp;lt;flag&amp;gt; defaults&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;line; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(echo &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; |awk &amp;#39;{print $1}&amp;#39; |sed -e &amp;#39;s#^-##&amp;#39;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; ! &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${line}&amp;quot;&lt;/span&gt; |egrep &lt;span class="s1"&gt;&amp;#39;\[.*\]&amp;#39;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;init&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="c"&gt;# it&amp;#39;s a flag. init with 0&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${opt}:&amp;quot;&lt;/span&gt; &lt;span class="c"&gt;# add : if opt has arg&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;init&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;  &lt;span class="c"&gt;# it has an arg. init with &amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${opts}${opt}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;varname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;arg_${opt:0:1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; ! &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${line}&amp;quot;&lt;/span&gt; |egrep &lt;span class="s1"&gt;&amp;#39;\. Default=&amp;#39;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${varname}=\&amp;quot;${init}\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(echo &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; |sed &amp;#39;s#^.*Default=\(\)#\1#g&amp;#39;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${varname}=\&amp;quot;${match}\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt; &amp;lt;&amp;lt;&amp;lt; &lt;span class="s2"&gt;&amp;quot;${usage}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Reset in case getopts has been used previously in the shell.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;OPTIND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Overwrite $arg_&amp;lt;flag&amp;gt; defaults with the actual CLI options&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;getopts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${opts}&amp;quot;&lt;/span&gt; opt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(echo &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;usage&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; |grep &amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;opt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${opt}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;?&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Invalid use of script: ${@} &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;varname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;arg_${opt:0:1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${!varname}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${OPTARG}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${OPTARG}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${default}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${varname}=\&amp;quot;${value}\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  debug &lt;span class="s2"&gt;&amp;quot;cli arg ${varname} = ($default) -&amp;gt; ${!varname}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;OPTIND-1&lt;span class="k"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;--&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;### Switches&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#####################################################################&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# debug mode&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${arg_d}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -x
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;7&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# help mode&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${arg_h}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;help&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Help using ${0}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;### Validation&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#####################################################################&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${arg_f}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;     &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt;   &lt;span class="s2"&gt;&amp;quot;Setting a filename with -f is required&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${LOG_LEVEL}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; emergency &lt;span class="s2"&gt;&amp;quot;Cannot continue without loglevel. &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;### Runtime&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#####################################################################&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Exit on error. Append ||true if you expect an error.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# set -e is safer than #!/bin/bash -e because that is nutralised if&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# someone runs your script like `bash yourscript.sh`&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Bash will remember &amp;amp; return the highest exitcode in a chain of pipes.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# This way you can catch the error in case mysqldump fails in `mysqldump |gzip`&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -o pipefail
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;debug &lt;span class="s2"&gt;&amp;quot;Info useful to developers for debugging the application, not useful during operations.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;info &lt;span class="s2"&gt;&amp;quot;Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;notice &lt;span class="s2"&gt;&amp;quot;Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;warning &lt;span class="s2"&gt;&amp;quot;Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. This is a debug message&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;error &lt;span class="s2"&gt;&amp;quot;Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;critical &lt;span class="s2"&gt;&amp;quot;Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;alert &lt;span class="s2"&gt;&amp;quot;Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;emergency &lt;span class="s2"&gt;&amp;quot;A \&amp;quot;panic\&amp;quot; condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Contribute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kvz/bash3boilerplate"&gt;Readme on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kvz/bash3boilerplate/blob/master/main.sh"&gt;View on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kvz/bash3boilerplate/edit/master/main.sh"&gt;Edit on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.github.com/kvz/bash3boilerplate/master/main.sh"&gt;Download from Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/1am-RnlR2eE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/02/26/introducing-bash3boilerplate/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[OSX Productivity: Dropbox your Screenshots]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/-x7tpxOFacg/" />
    <updated>2013-02-18T16:02:00+01:00</updated>
    <id>http://kvz.io/blog/2013/02/18/osx-productivity-dropbox-your-screenshots</id>
    <content type="html">&lt;p&gt;I often share screens with co-workers by Campfire, Github, or mail.
Visualizing something can save you a lot of typing. Show people
what button shade doesn&amp;#8217;t look quite right, instead of explaining in 1000+ characters.
Share a load graph without saving &amp;amp; attaching images, or handing out basic auth credentials.
The list goes on &amp;amp; on. Once you make it a joy to share, you&amp;#8217;ll find use-cases on
a daily basis, and it is my believe you&amp;#8217;ll lose less time on typing and miscommunication.&lt;/p&gt;

&lt;p&gt;At least.. that&amp;#8217;s what I&amp;#8217;m experiencing, using the following tricks.&lt;/p&gt;

&lt;!--More--&gt;


&lt;h2&gt;The Normal flow&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Press SHIFT + COMMAND + 4&lt;/li&gt;
&lt;li&gt;(optionally you spress SPACE to switch to Window-capturing)&lt;/li&gt;
&lt;li&gt;Drag an area that you want to share with co-workers&lt;/li&gt;
&lt;li&gt;A screenshot is saved to &lt;code&gt;~/Desktop&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;And now you&amp;#8217;ll have to find your way to the screenshot. That seems like effort.&lt;/p&gt;

&lt;h2&gt;The Better flow&lt;/h2&gt;

&lt;p&gt;But having many windows open, now it&amp;#8217;s a pain to access the screenshot.&lt;/p&gt;

&lt;p&gt;One thing you could do is make the Desktop folder more accessible by
adding it to your Dock. You can make it even better by setting it up as a
&lt;strong&gt;Fan&lt;/strong&gt;, ordered by &lt;strong&gt;Date Modfied&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, your latest screenshot will always be the bottom-first item from your
new Dock fan. Now you can drag &amp;amp; drop it right into your open Github/Campfire
app like a pro, without ever minimizing the apps your already working in,
or firing up Finder windows to hunt down your screen.&lt;/p&gt;

&lt;h2&gt;The Ultimate flow&lt;/h2&gt;

&lt;p&gt;To add even more sugar to this, you could tell OSX to save screenshots into Dropbox
by default. This way you can use screens as quick notes, distributed across
all of your machines; or you could tell Dropbox to quickly make a public
link of your screen, and share a URL with anyone.&lt;/p&gt;

&lt;h2&gt;Setup&lt;/h2&gt;

&lt;p&gt;Here&amp;#8217;s how to set up the Ultimate flow, assuming you have &lt;a href="http://db.tt/gkDsF6u"&gt;Dropbox&lt;/a&gt;.
Without Dropbox, it&amp;#8217;s still cool, just remove &lt;code&gt;/Dropbox&lt;/code&gt; from the following commands.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;mkdir -p ~/Dropbox/Screenshots/
&lt;/span&gt;&lt;span class='line'&gt;defaults write com.apple.screencapture location ~/Dropbox/Screenshots/
&lt;/span&gt;&lt;span class='line'&gt;killall SystemUIServer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now open your Dropbox in the GUI&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;open ~/Dropbox/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;Drag the &lt;code&gt;Screenshots&lt;/code&gt; next to your Downloads &amp;amp; Trash icons in your Dock&lt;/li&gt;
&lt;li&gt;Right click: Fan&lt;/li&gt;
&lt;li&gt;Right click: Date Modified&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Tight! Now make some screenshots as explained in the &lt;strong&gt;Normal flow&lt;/strong&gt; and
see them automatically added to the fan, most recent always the first
clickable item, and Dropbox syncing them up instantly.&lt;/p&gt;

&lt;h2&gt;Undo&lt;/h2&gt;

&lt;p&gt;Don&amp;#8217;t like it? Wow you are one tough customer. But here we go : )&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;defaults write com.apple.screencapture location ~/Desktop/
&lt;/span&gt;&lt;span class='line'&gt;killall SystemUIServer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And just remove the folder from your Dock. That&amp;#8217;s all : )&lt;/p&gt;

&lt;h2&gt;Alternatives&lt;/h2&gt;

&lt;p&gt;Now the article already mentions Dropbox is very optional, but of course
you can also substitute Dropbox with (free) competitors such as &lt;a href="https://twitter.com/predominant/status/303538082773340160"&gt;Sparkleshare&lt;/a&gt; if you&amp;#8217;re into that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/predominant/status/303538211966300162"&gt;It was also mentioned&lt;/a&gt;
by Graham Weldon that you can use
CloudApp for a similar workflow.
It&amp;#8217;s free &amp;amp; available in the &lt;a href="https://itunes.apple.com/us/app/cloud/id417602904?mt=12&amp;amp;ls=1"&gt;Mac App Store&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/-x7tpxOFacg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/02/18/osx-productivity-dropbox-your-screenshots/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Too many authentication failures for root]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/ObXmRiT2Vi4/" />
    <updated>2013-02-12T13:13:00+01:00</updated>
    <id>http://kvz.io/blog/2013/02/12/too-many-authentication-failures-for-root</id>
    <content type="html">&lt;p&gt;I recently had an annoying encounter with the error message:
&lt;code&gt;Too many authentication failures for root&lt;/code&gt;.
I found out this can be caused because you&amp;#8217;ve hoarded too many SSH keys : )&lt;/p&gt;

&lt;p&gt;So serves me right, but let&amp;#8217;s see what happens exactly.&lt;/p&gt;

&lt;!--more--&gt;


&lt;p&gt;Consider at this paste:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;» ssh -vvv root@67.23.163.74 2&amp;gt;&amp;amp;1 |egrep '(public|fail)'
debug3: Could not load "/Users/kevin/.ssh/id_rsa" as a RSA1 public key
debug3: Could not load "/Users/kevin/.ssh/id_dsa" as a RSA1 public key
debug1: Authentications that can continue: publickey,password
debug3: start over, passed a different list publickey,password
debug3: preferred publickey,keyboard-interactive,password
debug3: authmethod_lookup publickey
debug3: authmethod_is_enabled publickey
debug1: Next authentication method: publickey
debug1: Offering DSA public key: /Users/kevin/.ssh/id_dsa
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,password
debug1: Offering RSA public key: /Users/kevin/.ssh/kevin_201011_true
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,password
debug1: Offering RSA public key: /Users/kevin/.ssh/transkey.pem
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,password
debug1: Offering RSA public key: /Users/kevin/.ssh/kevin_201211_true
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,password
debug1: Offering RSA public key: /Users/kevin/.ssh/kevin_201205_true
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey,password
debug1: Offering RSA public key: /Users/kevin/.ssh/id_rsa
debug2: we sent a publickey packet, wait for reply
Received disconnect from 67.23.163.74: 2: Too many authentication failures for root
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It tries 6 different SSH keys it found laying around on my system before asking for a password.
I knew SSH automagiclly looks for the best way to authenticate you.
No problem there.&lt;/p&gt;

&lt;p&gt;But the serverside counts each try as a failure!
Apparently SSHD was configured to only allow so many (6) failures for a user (root),
hence SSH never even bothered asked for the password that should be working for this box.&lt;/p&gt;

&lt;p&gt;This server was freshly delivered by a colo provider, so I really could not get in any other way.
To fix, I could have cleaned up my keys, but instead I disabled login by Public key authentication:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ssh -o &lt;span class="nv"&gt;PubkeyAuthentication&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no root@67.23.163.74
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And this fixed the issue.&lt;/p&gt;

&lt;p&gt;Afterwards I could set up proper public keys and disable password login altogether.&lt;/p&gt;

&lt;p&gt;Tricky though, so I thought I&amp;#8217;d share : )&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/ObXmRiT2Vi4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/02/12/too-many-authentication-failures-for-root/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Keep Mounted Network Drives Alive on OSX]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/122jVBaIagc/" />
    <updated>2013-02-11T23:12:00+01:00</updated>
    <id>http://kvz.io/blog/2013/02/11/macosx-persistent-mounted-network-drives</id>
    <content type="html">&lt;p&gt;I love my NAS but because I tried to save a little money it does not &lt;a href="http://kvz.io/blog/2011/02/28/optimize-your-synology-for-downloading/"&gt;run SABnzbd&lt;/a&gt; very well.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve tried different approaches but find myself ending up downloading on OSX as it writes to a network share on my NAS. Too bad, but I&amp;#8217;m archiving this one under the section first world problems.&lt;/p&gt;

&lt;p&gt;The challenge I have now though, is when my Mac goes to sleep, my mounts disappear, and SABnzbd writes to the local filesystem instead. Cause as far as my downloading program could tell, it was already writing to a local filesystem, so it will just keep on doing that until my Mac&amp;#8217;s disk is at 100%.&lt;/p&gt;

&lt;p&gt;I wrote a little script to prevent that.&lt;/p&gt;

&lt;p&gt;You may not be running SABnzbd, but there are obviously many other
use cases where you want a network mount to persist.
Especially if you are automating something outside of the GUI.&lt;/p&gt;

&lt;p&gt;With some small adjustments this could work for Linux/NFS/SMB as well.&lt;/p&gt;

&lt;!-- More --&gt;


&lt;p&gt;Here we go&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt; (remounter.sh)&lt;/span&gt; &lt;a href='http://kvz.io/downloads/code/remounter.sh'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;span class='line-number'&gt;54&lt;/span&gt;
&lt;span class='line-number'&gt;55&lt;/span&gt;
&lt;span class='line-number'&gt;56&lt;/span&gt;
&lt;span class='line-number'&gt;57&lt;/span&gt;
&lt;span class='line-number'&gt;58&lt;/span&gt;
&lt;span class='line-number'&gt;59&lt;/span&gt;
&lt;span class='line-number'&gt;60&lt;/span&gt;
&lt;span class='line-number'&gt;61&lt;/span&gt;
&lt;span class='line-number'&gt;62&lt;/span&gt;
&lt;span class='line-number'&gt;63&lt;/span&gt;
&lt;span class='line-number'&gt;64&lt;/span&gt;
&lt;span class='line-number'&gt;65&lt;/span&gt;
&lt;span class='line-number'&gt;66&lt;/span&gt;
&lt;span class='line-number'&gt;67&lt;/span&gt;
&lt;span class='line-number'&gt;68&lt;/span&gt;
&lt;span class='line-number'&gt;69&lt;/span&gt;
&lt;span class='line-number'&gt;70&lt;/span&gt;
&lt;span class='line-number'&gt;71&lt;/span&gt;
&lt;span class='line-number'&gt;72&lt;/span&gt;
&lt;span class='line-number'&gt;73&lt;/span&gt;
&lt;span class='line-number'&gt;74&lt;/span&gt;
&lt;span class='line-number'&gt;75&lt;/span&gt;
&lt;span class='line-number'&gt;76&lt;/span&gt;
&lt;span class='line-number'&gt;77&lt;/span&gt;
&lt;span class='line-number'&gt;78&lt;/span&gt;
&lt;span class='line-number'&gt;79&lt;/span&gt;
&lt;span class='line-number'&gt;80&lt;/span&gt;
&lt;span class='line-number'&gt;81&lt;/span&gt;
&lt;span class='line-number'&gt;82&lt;/span&gt;
&lt;span class='line-number'&gt;83&lt;/span&gt;
&lt;span class='line-number'&gt;84&lt;/span&gt;
&lt;span class='line-number'&gt;85&lt;/span&gt;
&lt;span class='line-number'&gt;86&lt;/span&gt;
&lt;span class='line-number'&gt;87&lt;/span&gt;
&lt;span class='line-number'&gt;88&lt;/span&gt;
&lt;span class='line-number'&gt;89&lt;/span&gt;
&lt;span class='line-number'&gt;90&lt;/span&gt;
&lt;span class='line-number'&gt;91&lt;/span&gt;
&lt;span class='line-number'&gt;92&lt;/span&gt;
&lt;span class='line-number'&gt;93&lt;/span&gt;
&lt;span class='line-number'&gt;94&lt;/span&gt;
&lt;span class='line-number'&gt;95&lt;/span&gt;
&lt;span class='line-number'&gt;96&lt;/span&gt;
&lt;span class='line-number'&gt;97&lt;/span&gt;
&lt;span class='line-number'&gt;98&lt;/span&gt;
&lt;span class='line-number'&gt;99&lt;/span&gt;
&lt;span class='line-number'&gt;100&lt;/span&gt;
&lt;span class='line-number'&gt;101&lt;/span&gt;
&lt;span class='line-number'&gt;102&lt;/span&gt;
&lt;span class='line-number'&gt;103&lt;/span&gt;
&lt;span class='line-number'&gt;104&lt;/span&gt;
&lt;span class='line-number'&gt;105&lt;/span&gt;
&lt;span class='line-number'&gt;106&lt;/span&gt;
&lt;span class='line-number'&gt;107&lt;/span&gt;
&lt;span class='line-number'&gt;108&lt;/span&gt;
&lt;span class='line-number'&gt;109&lt;/span&gt;
&lt;span class='line-number'&gt;110&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#!/usr/bin/env bash -e&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Monitors mounts, checks if they&amp;#39;re writable, remounts if necessary.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# For OSX / AFP.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# If it had to remount, exits with code 1 so you can easily chain&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# other scripts in such an event. e.g.:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#  NASPASS=******** ./remounter.sh || ./restart_downloader.sh restart&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;_log &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;str&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${2}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;[$(date &amp;quot;&lt;/span&gt;+%Y-%m-%d %H:%M:%S&lt;span class="s2"&gt;&amp;quot;)] ${level}: ${str}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;info &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  _log &lt;span class="s2"&gt;&amp;quot;INFO&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;err  &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  _log &lt;span class="s2"&gt;&amp;quot; ERR&amp;quot;&lt;/span&gt;  &lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;crit &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  _log &lt;span class="s2"&gt;&amp;quot;CRIT&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt;;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${REBOOTONCRIT}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Warning, CRIT happened and reboot on crit was specified. &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Rebooting in 50 seconds&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    shutdown -r +50
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${NASSHARES}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;NASSHARES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;downloads video&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${NASHOST}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;      &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;NASHOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;nas.local&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${NASUSER}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;      &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;NASUSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${USER}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${STAMPFILE}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;STAMPFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.remounter.stamp&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${NASPASS}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;      &lt;span class="o"&gt;||&lt;/span&gt; crit &lt;span class="s2"&gt;&amp;quot;Please set the shares password like so: NASPASS=******** ${0}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${FORCEREMOUNT}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;FORCEREMOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${REBOOTONCRIT}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;REBOOTONCRIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;mount_exists &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/Volumes/${share}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(mount |egrep -i &amp;quot;&lt;/span&gt;^//&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NASUSER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NASHOST&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;share&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; on &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; |wc -l)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;mount_writable &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/Volumes/${share}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;stamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(date &amp;quot;&lt;/span&gt;+%Y-%m-%d %H:%M:%S&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;stampfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${dir}/${STAMPFILE}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${stamp}&amp;quot;&lt;/span&gt; &amp;gt; &lt;span class="s2"&gt;&amp;quot;${stampfile}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;  local &lt;/span&gt;&lt;span class="nv"&gt;found&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(cat &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;stampfile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;&amp;quot;${stampfile}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class="s2"&gt;&amp;quot;${stampfile}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${found}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${stamp}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function &lt;/span&gt;remount &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${1}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/Volumes/${share}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;stampfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${dir}/${STAMPFILE}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  info &lt;span class="s2"&gt;&amp;quot;remounting ${share}... &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;quot;${dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c"&gt;# Try 3 times because this happened once:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c"&gt;# //kevin@nas.local/downloads on /Volumes/downloads (afpfs, nodev, nosuid, mounted by kevin)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c"&gt;# //kevin@nas.local/video on /Volumes/video (afpfs, nodev, nosuid, mounted by kevin)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c"&gt;# //kevin@nas.local/downloads on /Volumes/downloads (afpfs, nodev, nosuid, mounted by kevin)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c"&gt;# //kevin@nas.local/video on /Volumes/video (afpfs, nodev, nosuid, mounted by kevin)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;for &lt;/span&gt;i in &lt;span class="sb"&gt;`&lt;/span&gt;seq 1 3&lt;span class="sb"&gt;`&lt;/span&gt;; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;umount -f &lt;span class="s2"&gt;&amp;quot;${dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;      &lt;/span&gt;sleep 1
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(mount_exists ${share})&amp;quot;&lt;/span&gt; -eq 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(mount_writable ${share})&amp;quot;&lt;/span&gt; -eq 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;    &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(mount_writable ${share})&amp;quot;&lt;/span&gt; -ne 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; crit &lt;span class="s2"&gt;&amp;quot;Could not unmount ${share}. Still writable&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(mount_exists ${share})&amp;quot;&lt;/span&gt; -ne 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; crit &lt;span class="s2"&gt;&amp;quot;Could not unmount ${share}. Still exists&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;mkdir -p &lt;span class="s2"&gt;&amp;quot;${dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  mount_afp -i &lt;span class="s2"&gt;&amp;quot;afp://${NASUSER}:${NASPASS}@${NASHOST}/${share}&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;for &lt;/span&gt;share in &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NASSHARES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${FORCEREMOUNT}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(mount_exists ${share})&amp;quot;&lt;/span&gt; -ne 1 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(mount_writable ${share})&amp;quot;&lt;/span&gt; -ne 1 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${missing}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;missing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${missing} &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;missing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${missing}${share}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    remount &lt;span class="s2"&gt;&amp;quot;${share}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;${missing}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;info &lt;span class="s2"&gt;&amp;quot;Mounts in tact. All good&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;info &lt;span class="s2"&gt;&amp;quot;Had to remount. &amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I &lt;a href="http://kvz.io/blog/2007/07/29/schedule-tasks-on-linux-using-crontab/"&gt;set up a cronjob&lt;/a&gt; so it
runs every minute like so:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;crontab -e
&lt;/span&gt;&lt;span class='line'&gt;* * * * * /location/remounter.sh &lt;span class="o"&gt;||&lt;/span&gt; /location/restart_downloader.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;To illustrate, here&amp;#8217;s &lt;code&gt;remounter.sh&lt;/code&gt; in action. This happened while I was away,
apparently my Mac went to sleep (otherwise you&amp;#8217;d see a stamp every minute),
and that totally broke the mounts afterwards, multiple times in different ways.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-25 22:48:02&lt;span class="o"&gt;]&lt;/span&gt; INFO: Mounts in tact. All good
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-25 22:49:01&lt;span class="o"&gt;]&lt;/span&gt; INFO: Mounts in tact. All good
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-26 06:38:00&lt;span class="o"&gt;]&lt;/span&gt; INFO: remounting downloads...
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-26 07:32:00&lt;span class="o"&gt;]&lt;/span&gt; INFO: remounting downloads...
&lt;/span&gt;&lt;span class='line'&gt;umount: /Volumes/downloads: not currently mounted
&lt;/span&gt;&lt;span class='line'&gt;/blogscripts/remounter.sh: line 55: /Volumes/downloads/.remounter.stamp: Permission denied
&lt;/span&gt;&lt;span class='line'&gt;cat: /Volumes/downloads/.remounter.stamp: No such file or directory
&lt;/span&gt;&lt;span class='line'&gt;/blogscripts/remounter.sh: line 55: /Volumes/downloads/.remounter.stamp: Permission denied
&lt;/span&gt;&lt;span class='line'&gt;cat: /Volumes/downloads/.remounter.stamp: No such file or directory
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-26 16:33:00&lt;span class="o"&gt;]&lt;/span&gt; INFO: remounting downloads...
&lt;/span&gt;&lt;span class='line'&gt;umount: /Volumes/downloads: not currently mounted
&lt;/span&gt;&lt;span class='line'&gt;/blogscripts/remounter.sh: line 55: /Volumes/downloads/.remounter.stamp: Permission denied
&lt;/span&gt;&lt;span class='line'&gt;cat: /Volumes/downloads/.remounter.stamp: No such file or directory
&lt;/span&gt;&lt;span class='line'&gt;/blogscripts/remounter.sh: line 55: /Volumes/downloads/.remounter.stamp: Permission denied
&lt;/span&gt;&lt;span class='line'&gt;cat: /Volumes/downloads/.remounter.stamp: No such file or directory
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-26 17:26:45&lt;span class="o"&gt;]&lt;/span&gt; INFO: remounting video...
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-26 17:26:48&lt;span class="o"&gt;]&lt;/span&gt; INFO: Had to remount.
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-26 17:27:04&lt;span class="o"&gt;]&lt;/span&gt; INFO: Mounts in tact. All good
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-26 18:21:04&lt;span class="o"&gt;]&lt;/span&gt; INFO: Mounts in tact. All good
&lt;/span&gt;&lt;span class='line'&gt;mount_afp: AFPMountURL returned error -1069, errno is -1069
&lt;/span&gt;&lt;span class='line'&gt;mount_afp: AFPMountURL returned error -5023, errno is -5023
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-27 01:45:02&lt;span class="o"&gt;]&lt;/span&gt; INFO: Mounts in tact. All good
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-27 01:46:04&lt;span class="o"&gt;]&lt;/span&gt; INFO: Mounts in tact. All good
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;2012-12-27 01:47:06&lt;span class="o"&gt;]&lt;/span&gt; INFO: Mounts in tact. All good
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Would be a great idea to &lt;a href="solo"&gt;/blog/2012/12/31/lock-your-cronjobs&lt;/a&gt; it.&lt;/p&gt;

&lt;p&gt;And that&amp;#8217;s that : )&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/122jVBaIagc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/02/11/macosx-persistent-mounted-network-drives/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Vagrant Tip: Sync VirtualBox Guest Additions]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/_-79-ASonXo/" />
    <updated>2013-01-16T13:43:00+01:00</updated>
    <id>http://kvz.io/blog/2013/01/16/vagrant-tip-keep-virtualbox-guest-additions-in-sync</id>
    <content type="html">&lt;p&gt;Quick tip. If you lose your &lt;a href="http://www.vagrantup.com/"&gt;Vagrant&lt;/a&gt;
mounts after kernel upgrades in your virtualbox,
you&amp;#8217;ll need to reinstall your &lt;a href="http://www.virtualbox.org/manual/ch04.html"&gt;VirtualBox Guest Additions&lt;/a&gt;.
Same is true when you upgrade Vagrant, etc.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s just a real pain and people usually avoid it by never upgrading.
Or delve in once they accidentally do.
But there&amp;#8217;s actually a nice &amp;amp; automated way of keeping your VM&amp;#8217;s guest additions in sync with
virtualbox.&lt;/p&gt;

&lt;!-- More --&gt;


&lt;p&gt;I was fed up with missing mountpoints and messages like these:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;vagrant up
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; Importing base box &lt;span class="s1"&gt;&amp;#39;ubuntu-12.04-64bit&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; The guest additions on this VM &lt;span class="k"&gt;do &lt;/span&gt;not match the install version of
&lt;/span&gt;&lt;span class='line'&gt;VirtualBox! This may cause things such as forwarded ports, shared
&lt;/span&gt;&lt;span class='line'&gt;folders, and more to not work properly. If any of those things fail on
&lt;/span&gt;&lt;span class='line'&gt;this machine, please update the guest additions and repackage the
&lt;/span&gt;&lt;span class='line'&gt;box.
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;Guest Additions Version: 4.1.22
&lt;/span&gt;&lt;span class='line'&gt;VirtualBox Version: 4.2.6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;So, &lt;a href="https://github.com/dotless-de/vagrant-vbguest"&gt;Vbguest plugin&lt;/a&gt; to the rescue!&lt;/p&gt;

&lt;p&gt;To install, you type this one time in the directory that
also keeps your &lt;code&gt;Vagrantfile&lt;/code&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# For vagrant &amp;lt; 1.1.5:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# vagrant gem install vagrant-vbguest&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# For vagrant 1.1.5+ (thanks Lars Haugseth):&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;vagrant plugin install vagrant-vbguest
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;On succesful execution, the output should look something like this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;Fetching: micromachine-1.0.4.gem &lt;span class="o"&gt;(&lt;/span&gt;100%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;Fetching: vagrant-vbguest-0.6.4.gem &lt;span class="o"&gt;(&lt;/span&gt;100%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;Successfully installed micromachine-1.0.4
&lt;/span&gt;&lt;span class='line'&gt;Successfully installed vagrant-vbguest-0.6.4
&lt;/span&gt;&lt;span class='line'&gt;2 gems installed
&lt;/span&gt;&lt;span class='line'&gt;Installing ri documentation &lt;span class="k"&gt;for &lt;/span&gt;micromachine-1.0.4...
&lt;/span&gt;&lt;span class='line'&gt;Installing ri documentation &lt;span class="k"&gt;for &lt;/span&gt;vagrant-vbguest-0.6.4...
&lt;/span&gt;&lt;span class='line'&gt;Installing RDoc documentation &lt;span class="k"&gt;for &lt;/span&gt;micromachine-1.0.4...
&lt;/span&gt;&lt;span class='line'&gt;Installing RDoc documentation &lt;span class="k"&gt;for &lt;/span&gt;vagrant-vbguest-0.6.4...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And that&amp;#8217;s it. From now on every &lt;code&gt;vagrant up&lt;/code&gt; will check &amp;amp; install
the correct guest additions right after booting:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; Waiting &lt;span class="k"&gt;for &lt;/span&gt;VM to boot. This can take a few minutes.
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; VM booted and ready &lt;span class="k"&gt;for &lt;/span&gt;use!
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; GuestAdditions 4.2.6 running --- OK.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And if it&amp;#8217;s outdated, here&amp;#8217;s what happens:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;vagrant up
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; Booting VM...
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; Waiting &lt;span class="k"&gt;for &lt;/span&gt;VM to boot. This can take a few minutes.
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; VM booted and ready &lt;span class="k"&gt;for &lt;/span&gt;use!
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; GuestAdditions versions on your host &lt;span class="o"&gt;(&lt;/span&gt;4.2.10&lt;span class="o"&gt;)&lt;/span&gt; and guest &lt;span class="o"&gt;(&lt;/span&gt;4.2.6&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;not match.
&lt;/span&gt;&lt;span class='line'&gt;stdin: is not a tty
&lt;/span&gt;&lt;span class='line'&gt;Reading package lists...
&lt;/span&gt;&lt;span class='line'&gt;Building dependency tree...
&lt;/span&gt;&lt;span class='line'&gt;Reading state information...
&lt;/span&gt;&lt;span class='line'&gt;linux-headers-3.2.0-23-generic is already the newest version.
&lt;/span&gt;&lt;span class='line'&gt;dkms is already the newest version.
&lt;/span&gt;&lt;span class='line'&gt;0 upgraded, 0 newly installed, 0 to remove and 126 not upgraded.
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; Copy iso file /Applications/VirtualBox.app/Contents/MacOS/VBoxGuestAdditions.iso into the box /tmp/VBoxGuestAdditions.iso
&lt;/span&gt;&lt;span class='line'&gt;stdin: is not a tty
&lt;/span&gt;&lt;span class='line'&gt;mount: warning: /mnt seems to be mounted &lt;span class="nb"&gt;read&lt;/span&gt;-only.
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;default&lt;span class="o"&gt;]&lt;/span&gt; Installing Virtualbox Guest Additions 4.2.10 - guest version is 4.2.6
&lt;/span&gt;&lt;span class='line'&gt;stdin: is not a tty
&lt;/span&gt;&lt;span class='line'&gt;Verifying archive integrity... All good.
&lt;/span&gt;&lt;span class='line'&gt;Uncompressing VirtualBox 4.2.10 Guest Additions &lt;span class="k"&gt;for &lt;/span&gt;Linux..........
&lt;/span&gt;&lt;span class='line'&gt;VirtualBox Guest Additions installer
&lt;/span&gt;&lt;span class='line'&gt;Removing installed version 4.2.6 of VirtualBox Guest Additions...
&lt;/span&gt;&lt;span class='line'&gt;Removing existing VirtualBox DKMS kernel modules ...done.
&lt;/span&gt;&lt;span class='line'&gt;Removing existing VirtualBox non-DKMS kernel modules ...done.
&lt;/span&gt;&lt;span class='line'&gt;Building the VirtualBox Guest Additions kernel modules ...done.
&lt;/span&gt;&lt;span class='line'&gt;Doing non-kernel setup of the Guest Additions ...done.
&lt;/span&gt;&lt;span class='line'&gt;You should restart your guest to make sure the new modules are actually used
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Tight! : )&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/_-79-ASonXo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2013/01/16/vagrant-tip-keep-virtualbox-guest-additions-in-sync/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Lock your Cronjobs, Enjoy your Sleep]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/F5A1KKLRro4/" />
    <updated>2012-12-31T11:15:00+01:00</updated>
    <id>http://kvz.io/blog/2012/12/31/lock-your-cronjobs</id>
    <content type="html">&lt;p&gt;If you use EC2 you may have heard of Tim Kay&amp;#8217;s &lt;a href="http://timkay.com/aws/"&gt;aws&lt;/a&gt; commandline tool.
It provides access to most of Amazon&amp;#8217;s API and is less cumbersome
than Amazon&amp;#8217;s own CLI utilities in day to day use.&lt;/p&gt;

&lt;p&gt;A lesser known tool by Tim Kay is &lt;a href="http://timkay.com/solo/"&gt;solo&lt;/a&gt;. It&amp;#8217;s basically one line of Perl,
but it&amp;#8217;s incredibly useful to defeat a common problem with cronjobs: overlap.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;You&amp;#8217;ve probably dealt with this before; you write a pretty neat &lt;code&gt;yourscript.sh&lt;/code&gt;,
schedule it to run every or so minute on your production server.
One night, your server reaches a load of 90 and you get pagerdutied to fix this.&lt;/p&gt;

&lt;p&gt;You login, which takes about 15 minutes, succeed executng &lt;code&gt;ps auxf&lt;/code&gt;,
and it appears your server now has &lt;code&gt;8325&lt;/code&gt; instances of &lt;code&gt;yourscript.sh&lt;/code&gt; running.
What happened?!&lt;/p&gt;

&lt;p&gt;Maybe there was an infinite loop in your script, maybe there were NFS timeouts,
you tried to update a database that had write-locks during backup,
but whatever the cause; there was overlap &lt;code&gt;8324&lt;/code&gt; times, and this should never happen.
Not even once.&lt;/p&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;

&lt;p&gt;One way to defeat it, is to write perfect code and have 0 external dependecies that can increase
your script&amp;#8217;s execution time.&lt;/p&gt;

&lt;p&gt;But since that is never going to happen ; ) I recommend taking a look at &lt;code&gt;solo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Tim Kay realised that operating systems typically can only ever have 1 process listening on a port,
and makes clever use of that as a locking mechanism.&lt;/p&gt;

&lt;h2&gt;The Flow&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/usr/bin/solo -port=3000 /path/to/yourscript.sh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Solo tries to open port 3000&lt;/li&gt;
&lt;li&gt;Can it open port 3000?

&lt;ul&gt;
&lt;li&gt;Start &lt;code&gt;yourscript.sh&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Can&amp;#8217;t open port 3000?

&lt;ul&gt;
&lt;li&gt;Never mind, &lt;code&gt;yourscript.sh&lt;/code&gt; is probably still running, will try again next time&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Naturally this beats working with lock/PID files, because an open port is directly tied
to a runnin process, and chances of inconsistency and having to detect and cleanup
orphaned PID files, are zero.&lt;/p&gt;

&lt;h2&gt;The Example&lt;/h2&gt;

&lt;p&gt;Your &lt;a href="http://kvz.io/blog/2007/07/29/schedule-tasks-on-linux-using-crontab/"&gt;crontab&lt;/a&gt; could e.g. look like this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;crontab -e
&lt;/span&gt;&lt;span class='line'&gt;*    * * * * /usr/bin/solo -port&lt;span class="o"&gt;=&lt;/span&gt;3001 /path/to/yourscript1.sh
&lt;/span&gt;&lt;span class='line'&gt;*    * * * * /usr/bin/solo -port&lt;span class="o"&gt;=&lt;/span&gt;3002 /path/to/yourscript2.sh
&lt;/span&gt;&lt;span class='line'&gt;*/10 * * * * /usr/bin/solo -port&lt;span class="o"&gt;=&lt;/span&gt;3003 /path/to/yourscript3.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You can now be sure that only one instance of each script will run at any given time.&lt;/p&gt;

&lt;p&gt;Clever chaps may realise this can be used as a keepalive system for daemon-like
scripts. However I suggest looking into
&lt;a href="http://mmonit.com/monit/"&gt;monit&lt;/a&gt; or
&lt;a href="http://kvz.io/blog/2009/12/15/run-nodejs-as-a-service-on-ubuntu-karmic/"&gt;upstart&lt;/a&gt; for that.&lt;/p&gt;

&lt;h2&gt;The Installation&lt;/h2&gt;

&lt;p&gt;This is what makes solo great, it has basically 0 dependencies
(ok Perl, but I&amp;#8217;ll assume you have that) and is a breeze to deploy.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo curl -q https://raw.github.com/timkay/solo/master/solo -o /usr/bin/solo &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo chmod +x &lt;span class="nv"&gt;$_&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Happy &lt;code&gt;crontab -e&lt;/code&gt;ing, and happy dreams with few pagerduties, you&amp;#8217;ve earned it : )&lt;/p&gt;

&lt;h2&gt;The Alternative&lt;/h2&gt;

&lt;p&gt;As Jason mentioned, if your jobs don&amp;#8217;t need to necessarily finish running, but just restart without overlap, another option is to use &lt;a href="http://linux.die.net/man/1/timeout"&gt;timeout&lt;/a&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;crontab -e
&lt;/span&gt;&lt;span class='line'&gt;* * * * * timeout -s9 50s /path/to/yourscript1.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;The Next Level: Go Distributed with Cronlock&lt;/h2&gt;

&lt;p&gt;Ok so solo is the bomb in terms of simplicity for running 1 instance of 1 script on 1 server.&lt;/p&gt;

&lt;p&gt;But what if you want to make sure only 1 instance of 1 script can run throughout many servers?
Install the cronjobs on just one server? Hm.. what if it goes down. That means
someone will have to intervene, chances are they will forget, and your nodes aren&amp;#8217;t really expendable.&lt;/p&gt;

&lt;p&gt;Especially in volatile environments where nodes come &amp;amp; go as they please, you want cronjobs to be the
responsibility of the collective, not just 1 machine.&lt;/p&gt;

&lt;p&gt;For this purpose I wrote &lt;a href="https://github.com/kvz/cronlock"&gt;Cronlock&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;The good&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can deploy all nodes equally, install all cronjobs on all servers, if a node goes down, another will make sure your jobs are executed&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;The bad&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It relies on a central redis server. If your cluster already relies on redis,
you&amp;#8217;re not adding reliability or a &lt;a href="http://en.wikipedia.org/wiki/Single_point_of_failure"&gt;SPOF&lt;/a&gt;.
If your cluster doesn&amp;#8217;t, reconsider using Cronlock.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;The ugly&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I use straight up BASH for everything. I don&amp;#8217;t even use &lt;code&gt;redis-cli&lt;/code&gt; to communicate with Redis.
This is because I want deployment to be as easy as with solo. Just a&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo curl -q https://raw.github.com/kvz/cronlock/master/cronlock -o /usr/bin/cronlock &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo chmod +x &lt;span class="nv"&gt;$_&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;and you&amp;#8217;re set.&lt;/p&gt;

&lt;p&gt;You can visit &lt;a href="https://github.com/kvz/cronlock"&gt;Cronlock on Github&lt;/a&gt; for docs on how configure it.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/F5A1KKLRro4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2012/12/31/lock-your-cronjobs/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Installing Hubot on Ubuntu]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/fAowLv3uNKQ/" />
    <updated>2012-11-20T13:27:00+01:00</updated>
    <id>http://kvz.io/blog/2012/11/20/installing-hubot-on-ubuntu</id>
    <content type="html">&lt;p&gt;&lt;img src="https://secure.gravatar.com/avatar/64afcfdf8e40d081a80961eae290890c?s=80&amp;amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-80.png" title="Hubot" alt="Hubot" style="float: left; margin-right: 10px;"/&gt;&lt;/p&gt;

&lt;p&gt;We used to run
&lt;a href="https://github.com/github/hubot/wiki/Deploying-Hubot-onto-Heroku"&gt;Hubot on Heroko&lt;/a&gt; until
it crashed, not sure what happened exactly but we didn&amp;#8217;t bother bring it back due more pressing issues
within our company.&lt;/p&gt;

&lt;p&gt;Then I saw one of the most georgeous presentations ever,
&lt;a href="https://speakerdeck.com/tanoku/intergalactic-javascript-robots-from-outer-space"&gt;Intergalactic Javascript Robots from Outer Space&lt;/a&gt;,
and it got me excited to run a &lt;a href="http://hubot.github.com/"&gt;Hubot&lt;/a&gt; again.&lt;/p&gt;

&lt;!--more--&gt;


&lt;p&gt;This time I wanted to &lt;a href="https://github.com/github/hubot/wiki/Deploying-Hubot-onto-UNIX"&gt;Deploy Hubot onto UNIX&lt;/a&gt;.
I followed the excellent article, and made some adjustments below in this blogpost to
accomodate better system integration and copypastability : )&lt;/p&gt;

&lt;h2&gt;First off&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m assuming you use Campfire. Let&amp;#8217;s create a bot user by the name &lt;code&gt;hubot&lt;/code&gt; there.
Make sure has a working email address because Campfire will want to validate it.&lt;/p&gt;

&lt;p&gt;Hint: It&amp;#8217;s fun to give your &lt;code&gt;hubot@yourcompany.com&lt;/code&gt; a
&lt;a href="https://secure.gravatar.com/avatar/64afcfdf8e40d081a80961eae290890c?s=80&amp;amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-80.png"&gt;nice avatar&lt;/a&gt;
at &lt;a href="http://gravatar.com"&gt;gravatar.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All done? Let&amp;#8217;s install!&lt;/p&gt;

&lt;h2&gt;Install&lt;/h2&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Prerequisites&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;aptitude install build-essential libssl-dev git-core redis-server libexpat1-dev logtail
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# If you don&amp;#39;t have node 0.6+&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;v0.6.9&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;NODE_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;node-${NODE_VERSION}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;pushd&lt;/span&gt; /usr/local
&lt;/span&gt;&lt;span class='line'&gt;  wget http://nodejs.org/dist/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.gz
&lt;/span&gt;&lt;span class='line'&gt;  tar xf &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.gz -C src &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;src/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  ./configure &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make install
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Coffeescript&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;npm install -g coffee-script
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Hubot&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;pushd&lt;/span&gt; /usr/local
&lt;/span&gt;&lt;span class='line'&gt;  git clone git://github.com/github/hubot.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;hubot
&lt;/span&gt;&lt;span class='line'&gt;  npm install
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Note that npm is bundled with node since &lt;a href="http://blog.nodejs.org/2011/11/25/node-v0-6-3/"&gt;v0.6.3&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Hubot system user&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;adduser --disabled-password --gecos &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; hubot
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Upstart script&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF &amp;gt; /etc/init/hubot.conf&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;description &amp;quot;Hubot Campfire bot&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;# Campfire-specific environment variables. Change these:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env HUBOT_CAMPFIRE_ACCOUNT=&amp;#39;companyname&amp;#39; # the one in: &amp;lt;companyname&amp;gt;.campfirenow.com&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env HUBOT_CAMPFIRE_ROOMS=&amp;#39;123456&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env HUBOT_CAMPFIRE_TOKEN=&amp;#39;afafafafafafafafafafcdcdcdcdcdcdcdcdcdc&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;# Subscribe to these upstart events&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;# This will make Hubot start on system boot&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;start on filesystem or runlevel [2345]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;stop on runlevel [!2345]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;# Path to Hubot installation&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env HUBOT_DIR=&amp;#39;/usr/local/hubot/&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env HUBOT=&amp;#39;bin/hubot&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env ADAPTER=&amp;#39;campfire&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env HUBOT_USER=&amp;#39;hubot&amp;#39; # system account&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env HUBOT_NAME=&amp;#39;bot&amp;#39; # what hubot listens to&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;env PORT=&amp;#39;5555&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;# Keep the process alive, limit to 5 restarts in 60s&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;respawn&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;respawn limit 5 60&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;exec start-stop-daemon --start --chuid \${HUBOT_USER} --chdir \${HUBOT_DIR} \&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  --exec \${HUBOT_DIR}\${HUBOT} -- --name \${HUBOT_NAME} --adapter \${ADAPTER}  &amp;gt;&amp;gt; /var/log/hubot.log 2&amp;gt;&amp;amp;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now don&amp;#8217;t forget to &lt;code&gt;vim /etc/init/hubot.conf&lt;/code&gt; and change the 3 &lt;code&gt;HUBOT_CAMPFIRE_&lt;/code&gt; environment variables.&lt;/p&gt;

&lt;p&gt;To start, type:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;start hubot
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;To check the log, type:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;logtail /var/log/hubot.log
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Use&lt;/h2&gt;

&lt;p&gt;Now check Campfire to see if &lt;code&gt;Hubot entered the room&lt;/code&gt;, and tell him to send you an image; type:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;bot: image me donuts
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Some other commands to get you started may be retrieved by issuing:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;bot &lt;span class="nb"&gt;help&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This will show you:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;bot &amp;lt;user&amp;gt; is a badass guitarist - assign a role to a user
&lt;/span&gt;&lt;span class='line'&gt;bot &amp;lt;user&amp;gt; is not a badass guitarist - remove a role from a user
&lt;/span&gt;&lt;span class='line'&gt;bot animate me &amp;lt;query&amp;gt; - The same thing as &lt;span class="sb"&gt;`&lt;/span&gt;image me&lt;span class="sb"&gt;`&lt;/span&gt;, except adds a few parameters to try to &lt;span class="k"&gt;return &lt;/span&gt;an animated GIF instead.
&lt;/span&gt;&lt;span class='line'&gt;bot convert me &amp;lt;expression&amp;gt; to &amp;lt;units&amp;gt; - Convert expression to given units.
&lt;/span&gt;&lt;span class='line'&gt;bot die - End hubot process
&lt;/span&gt;&lt;span class='line'&gt;bot &lt;span class="nb"&gt;echo&lt;/span&gt; &amp;lt;text&amp;gt; - Reply back with &amp;lt;text&amp;gt;
&lt;/span&gt;&lt;span class='line'&gt;bot &lt;span class="nb"&gt;help&lt;/span&gt; - Displays all of the &lt;span class="nb"&gt;help &lt;/span&gt;commands that Hubot knows about.
&lt;/span&gt;&lt;span class='line'&gt;bot &lt;span class="nb"&gt;help&lt;/span&gt; &amp;lt;query&amp;gt; - Displays all &lt;span class="nb"&gt;help &lt;/span&gt;commands that match &amp;lt;query&amp;gt;.
&lt;/span&gt;&lt;span class='line'&gt;bot image me &amp;lt;query&amp;gt; - The Original. Queries Google Images &lt;span class="k"&gt;for&lt;/span&gt; &amp;lt;query&amp;gt; and returns a random top result.
&lt;/span&gt;&lt;span class='line'&gt;bot map me &amp;lt;query&amp;gt; - Returns a map view of the area returned by &lt;span class="sb"&gt;`&lt;/span&gt;query&lt;span class="sb"&gt;`&lt;/span&gt;.
&lt;/span&gt;&lt;span class='line'&gt;bot math me &amp;lt;expression&amp;gt; - Calculate the given expression.
&lt;/span&gt;&lt;span class='line'&gt;bot mustache me &amp;lt;query&amp;gt; - Searches Google Images &lt;span class="k"&gt;for &lt;/span&gt;the specified query and mustaches it.
&lt;/span&gt;&lt;span class='line'&gt;bot mustache me &amp;lt;url&amp;gt; - Adds a mustache to the specified URL.
&lt;/span&gt;&lt;span class='line'&gt;bot ping - Reply with pong
&lt;/span&gt;&lt;span class='line'&gt;bot pug bomb N - get N pugs
&lt;/span&gt;&lt;span class='line'&gt;bot pug me - Receive a pug
&lt;/span&gt;&lt;span class='line'&gt;bot show storage - Display the contents that are persisted in the brain
&lt;/span&gt;&lt;span class='line'&gt;bot show users - Display all users that hubot knows about
&lt;/span&gt;&lt;span class='line'&gt;bot the rules - Make sure hubot still knows the rules.
&lt;/span&gt;&lt;span class='line'&gt;bot &lt;span class="nb"&gt;time&lt;/span&gt; - Reply with current &lt;span class="nb"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;bot translate me &amp;lt;phrase&amp;gt; - Searches &lt;span class="k"&gt;for &lt;/span&gt;a translation &lt;span class="k"&gt;for &lt;/span&gt;the &amp;lt;phrase&amp;gt; and &lt;span class="k"&gt;then &lt;/span&gt;prints that bad boy out.
&lt;/span&gt;&lt;span class='line'&gt;bot translate me from &amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&amp;gt; into &amp;lt;target&amp;gt; &amp;lt;phrase&amp;gt; - Translates &amp;lt;phrase&amp;gt; from &amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&amp;gt; into &amp;lt;target&amp;gt;. Both &amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&amp;gt; and &amp;lt;target&amp;gt; are optional
&lt;/span&gt;&lt;span class='line'&gt;bot who is &amp;lt;user&amp;gt; - see what roles a user has
&lt;/span&gt;&lt;span class='line'&gt;bot youtube me &amp;lt;query&amp;gt; - Searches YouTube &lt;span class="k"&gt;for &lt;/span&gt;the query and returns the video embed link.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Going forward&lt;/h2&gt;

&lt;p&gt;You can write your own &lt;a href="https://github.com/github/hubot-scripts#readme"&gt;Hubot Scripts&lt;/a&gt;, or use
&lt;a href="http://hubot-script-catalog.herokuapp.com/"&gt;those by others&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy hubbing : )&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/fAowLv3uNKQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2012/11/20/installing-hubot-on-ubuntu/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Highlevel testing with CasperJS]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/A-nulBr6k10/" />
    <updated>2012-11-03T12:29:00+01:00</updated>
    <id>http://kvz.io/blog/2012/11/03/highlevel-testing-with-casperjs</id>
    <content type="html">&lt;p&gt;If you&amp;#8217;ve written a webapp and you want to ensure that critical parts such as the signup process
stay working, the best would be to have an actual user go through that process every time you
change your codebase. But since that&amp;#8217;s is both tedious &amp;amp; expensive, the second best thing is to automate
a chrome browser (webkit engine anyway) to do this for you, and upload screenshots if anything unexpected
happens.&lt;/p&gt;

&lt;p&gt;Welcome to CasperJS!&lt;/p&gt;

&lt;!--more--&gt;


&lt;p&gt;From the &lt;a href="http://casperjs.org/"&gt;CasperJS&lt;/a&gt; website: &amp;#8220;Casperjs is an open source navigation scripting &amp;amp; testing utility written in Javascript and based on &lt;a href="http://www.phantomjs.org/"&gt;PhantomJS&lt;/a&gt; — the scriptable headless WebKit engine. It eases the process of defining a full navigation scenario and provides useful high-level functions, methods &amp;amp; syntactic sugar&amp;#8221;.&lt;/p&gt;

&lt;h2&gt;Install&lt;/h2&gt;

&lt;h3&gt;OSX&lt;/h3&gt;

&lt;p&gt;If you use &lt;a href="http://mxcl.github.com/homebrew/"&gt;Homebrew&lt;/a&gt;, you can install both CasperJS and PhantomJS using this command:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install casperjs
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Ubuntu&lt;/h3&gt;

&lt;p&gt;To install both PhantomJS and CasperJS into &lt;code&gt;/usr/local&lt;/code&gt; with this layout:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;/usr/local/bin/casperjs  -&amp;gt; /usr/local/casperjs-1.0.0/bin/casperjs
&lt;/span&gt;&lt;span class='line'&gt;/usr/local/bin/phantomjs -&amp;gt; /usr/local/phantomjs-1.8.0-linux-x86_64/bin/phantomjs
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Please execute the following
(Warning: purges all previous versions of CasperJS inside /usr/local/)&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;PHANTOM_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1.8.0&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;PHANTOM_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;phantomjs-${PHANTOM_VERSION}-linux-x86_64&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(/usr/local/bin/phantomjs --version 2&amp;gt;/dev/null)&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${PHANTOM_VERSION}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;DEBIAN_FRONTEND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noninteractive apt-get -y --force-yes install libfontconfig1-dev
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;pushd&lt;/span&gt; /usr/local/
&lt;/span&gt;&lt;span class='line'&gt;    wget --quiet http://phantomjs.googlecode.com/files/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHANTOM_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.bz2
&lt;/span&gt;&lt;span class='line'&gt;    tar -jxvf &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHANTOM_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.bz2 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHANTOM_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.bz2*
&lt;/span&gt;&lt;span class='line'&gt;    ln -nfs /usr/local/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHANTOM_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/bin/phantomjs /usr/local/bin/phantomjs
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;CASPER_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;CASPER_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;casperjs-${CASPER_VERSION}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(/usr/local/bin/casperjs --version 2&amp;gt;/dev/null)&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${CASPER_VERSION}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;pushd&lt;/span&gt; /usr/local/
&lt;/span&gt;&lt;span class='line'&gt;    rm -rf *casperjs*
&lt;/span&gt;&lt;span class='line'&gt;    wget --quiet https://github.com/n1k0/casperjs/tarball/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CASPER_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    tar -zxvf &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CASPER_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CASPER_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;*
&lt;/span&gt;&lt;span class='line'&gt;    mv *casperjs* /usr/local/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CASPER_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="c"&gt;# n1k0-casperjs-e629586&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    ln -nfs /usr/local/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CASPER_BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/bin/casperjs /usr/local/bin/casperjs
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;phantomjs --version
&lt;/span&gt;&lt;span class='line'&gt;casperjs --version
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Use&lt;/h2&gt;

&lt;h3&gt;Notes&lt;/h3&gt;

&lt;p&gt;You can write CaspjerJS scripts in Javascript or &lt;a href="http://coffeescript.org/"&gt;Coffeescript&lt;/a&gt;.
CasperJS will just switch interpreters based on the extension of the script you feed it.
For small projects like these I prefer Coffeescript.&lt;/p&gt;

&lt;p&gt;Note that CasperJS is not &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; and though compatible with require, you
&lt;a href="https://github.com/n1k0/casperjs/issues/247"&gt;cannot use any npm modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To check if your &lt;code&gt;.coffee&lt;/code&gt; files are valid, I recommend running them through
&lt;a href="http://www.coffeelint.org/"&gt;coffeelint&lt;/a&gt; (&lt;code&gt;npm install -g coffeelint&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Make sure you &lt;a href="https://github.com/n1k0/casperjs/issues/291#issuecomment-10994973"&gt;run at least RC3&lt;/a&gt;
if you want to capture screenshots of timeouts as well.&lt;/p&gt;

&lt;h3&gt;Example&lt;/h3&gt;

&lt;p&gt;Here&amp;#8217;s an example script that shows some different tricks, I&amp;#8217;ve commented
along the way. Some gems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anytime a testcase fails, a &lt;code&gt;.png&lt;/code&gt; is saved. CasperJS will exit with code &lt;code&gt;1&lt;/code&gt;
so it&amp;#8217;s really easy to detect a fail then upload this screenshot to &lt;a href="http://campfirenow.com/"&gt;campfire&lt;/a&gt;
for example. This is possible using just &lt;code&gt;curl&lt;/code&gt; and your campfire api keys.&lt;/li&gt;
&lt;li&gt;Anytime a page contains: &lt;code&gt;Error&lt;/code&gt; or &lt;code&gt;Exception&lt;/code&gt;, a fail is automatically
triggered without the need to write additional asserts for this. It can be
disabled on a URL basis (in this case &lt;code&gt;/nonexistent&lt;/code&gt; is
allowed to throw these texts).&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;span class='line-number'&gt;54&lt;/span&gt;
&lt;span class='line-number'&gt;55&lt;/span&gt;
&lt;span class='line-number'&gt;56&lt;/span&gt;
&lt;span class='line-number'&gt;57&lt;/span&gt;
&lt;span class='line-number'&gt;58&lt;/span&gt;
&lt;span class='line-number'&gt;59&lt;/span&gt;
&lt;span class='line-number'&gt;60&lt;/span&gt;
&lt;span class='line-number'&gt;61&lt;/span&gt;
&lt;span class='line-number'&gt;62&lt;/span&gt;
&lt;span class='line-number'&gt;63&lt;/span&gt;
&lt;span class='line-number'&gt;64&lt;/span&gt;
&lt;span class='line-number'&gt;65&lt;/span&gt;
&lt;span class='line-number'&gt;66&lt;/span&gt;
&lt;span class='line-number'&gt;67&lt;/span&gt;
&lt;span class='line-number'&gt;68&lt;/span&gt;
&lt;span class='line-number'&gt;69&lt;/span&gt;
&lt;span class='line-number'&gt;70&lt;/span&gt;
&lt;span class='line-number'&gt;71&lt;/span&gt;
&lt;span class='line-number'&gt;72&lt;/span&gt;
&lt;span class='line-number'&gt;73&lt;/span&gt;
&lt;span class='line-number'&gt;74&lt;/span&gt;
&lt;span class='line-number'&gt;75&lt;/span&gt;
&lt;span class='line-number'&gt;76&lt;/span&gt;
&lt;span class='line-number'&gt;77&lt;/span&gt;
&lt;span class='line-number'&gt;78&lt;/span&gt;
&lt;span class='line-number'&gt;79&lt;/span&gt;
&lt;span class='line-number'&gt;80&lt;/span&gt;
&lt;span class='line-number'&gt;81&lt;/span&gt;
&lt;span class='line-number'&gt;82&lt;/span&gt;
&lt;span class='line-number'&gt;83&lt;/span&gt;
&lt;span class='line-number'&gt;84&lt;/span&gt;
&lt;span class='line-number'&gt;85&lt;/span&gt;
&lt;span class='line-number'&gt;86&lt;/span&gt;
&lt;span class='line-number'&gt;87&lt;/span&gt;
&lt;span class='line-number'&gt;88&lt;/span&gt;
&lt;span class='line-number'&gt;89&lt;/span&gt;
&lt;span class='line-number'&gt;90&lt;/span&gt;
&lt;span class='line-number'&gt;91&lt;/span&gt;
&lt;span class='line-number'&gt;92&lt;/span&gt;
&lt;span class='line-number'&gt;93&lt;/span&gt;
&lt;span class='line-number'&gt;94&lt;/span&gt;
&lt;span class='line-number'&gt;95&lt;/span&gt;
&lt;span class='line-number'&gt;96&lt;/span&gt;
&lt;span class='line-number'&gt;97&lt;/span&gt;
&lt;span class='line-number'&gt;98&lt;/span&gt;
&lt;span class='line-number'&gt;99&lt;/span&gt;
&lt;span class='line-number'&gt;100&lt;/span&gt;
&lt;span class='line-number'&gt;101&lt;/span&gt;
&lt;span class='line-number'&gt;102&lt;/span&gt;
&lt;span class='line-number'&gt;103&lt;/span&gt;
&lt;span class='line-number'&gt;104&lt;/span&gt;
&lt;span class='line-number'&gt;105&lt;/span&gt;
&lt;span class='line-number'&gt;106&lt;/span&gt;
&lt;span class='line-number'&gt;107&lt;/span&gt;
&lt;span class='line-number'&gt;108&lt;/span&gt;
&lt;span class='line-number'&gt;109&lt;/span&gt;
&lt;span class='line-number'&gt;110&lt;/span&gt;
&lt;span class='line-number'&gt;111&lt;/span&gt;
&lt;span class='line-number'&gt;112&lt;/span&gt;
&lt;span class='line-number'&gt;113&lt;/span&gt;
&lt;span class='line-number'&gt;114&lt;/span&gt;
&lt;span class='line-number'&gt;115&lt;/span&gt;
&lt;span class='line-number'&gt;116&lt;/span&gt;
&lt;span class='line-number'&gt;117&lt;/span&gt;
&lt;span class='line-number'&gt;118&lt;/span&gt;
&lt;span class='line-number'&gt;119&lt;/span&gt;
&lt;span class='line-number'&gt;120&lt;/span&gt;
&lt;span class='line-number'&gt;121&lt;/span&gt;
&lt;span class='line-number'&gt;122&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='coffeescript'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;## Setup&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cm"&gt;########################################################################&lt;/span&gt;&lt;span class="c1"&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;utils  = &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;utils&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;casper = &lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;casper&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;verbose: &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;logLevel: &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;warning&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;exitOnError: &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;safeLogs: &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;viewportSize:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;width: &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;height: &lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;testhost   = &lt;/span&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;testhost&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;screenshot = &lt;/span&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;screenfile&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Using testhost: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;info&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Using screenshot: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;screenshot&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;info&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;testhost&lt;/span&gt; &lt;span class="o"&gt;or&lt;/span&gt; &lt;span class="o"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;screenshot&lt;/span&gt; &lt;span class="o"&gt;or&lt;/span&gt; &lt;span class="o"&gt;not&lt;/span&gt; &lt;span class="sr"&gt;/\.(png)$/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="nx"&gt;screenshot&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;casper&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Usage: $ casperjs test project.coffee --ignore-ssl-errors=yes --testhost=&amp;lt;testhost&amp;gt; --screenfile=&amp;lt;screenshot.png&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;## Hooks&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cm"&gt;########################################################################&lt;/span&gt;&lt;span class="c1"&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Capture screens from all fails&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;on&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;fail&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;(failure) -&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Capture screens from timeouts from e.g. @waitUntilVisible&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Requires RC3 or higher.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;casper.options.onWaitTimeout = &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@capture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screenshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@exit&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Scan for the word notice|warning|error|exception by default&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;on&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;step.complete&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;(page) -&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;# Skip urls that can contain &amp;#39;error&amp;#39;/&amp;#39;exception&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;u = &lt;/span&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCurrentUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/nonexistent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertEval&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;div#content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/(notice|warning|error|exception)/i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;no notices, warnings, errors or exceptions in &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;## Testcases&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cm"&gt;########################################################################&lt;/span&gt;&lt;span class="c1"&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# This is an app that has everything (even the /news page) behind a login.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# try to access nonexistent when logged in (don&amp;#39;t 404, we only tell customers what exists and what not)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/nonexistent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertHttpStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;nonexistent should 302 when logged not in (can&amp;#39;t show guests what exists)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertUrlMatch&lt;/span&gt; &lt;span class="sr"&gt;/\/customers\/login/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;redirect to login&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# open /news/ without login, errors out, should go to login,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/news/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertTextExists&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;I could not give you access to&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;cannot access news without login&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertUrlMatch&lt;/span&gt; &lt;span class="sr"&gt;/\/customers\/login/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;redirect to login&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertTitle&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Please login&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;login page title is the one expected&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertExists&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;form[action=\&amp;quot;/customers/login/\&amp;quot;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;login page must have a form with customer/login action&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@fill&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;form[action=\&amp;quot;/customers/login/\&amp;quot;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;data[Customer][username]&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;janedoe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;data[Customer][password]&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;jsdi32ld!&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# redirect to landing page /news/&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertUrlMatch&lt;/span&gt; &lt;span class="sr"&gt;/\/news/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;redirected to landing page after login&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# notice login twice&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/customers/login&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertTextExists&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;You are already logged in&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;notice already logged in&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# try to access admin page&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/admin/tickets&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertTextExists&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;I could not give you access to &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;prohibit to access admin page&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# try to access nonexistent when logged in&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/nonexistent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertHttpStatus&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;nonexistent should 404 when logged in&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# dashboard has panels&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/customers/dashboard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertTitle&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Dashboard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;customer dashboard title is ok&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertEvalEquals&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;__utils__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.user-dashboard div.accordion-heading&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;found 8 customer dashboard panels&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# calculate storage price&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/storage_accounts/add&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@evaluate&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="s"&gt;StorageAccountBytesMax&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;10737418240&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="s"&gt;StorageAccountPassword&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dlfksfag!1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="s"&gt;StorageAccountEmail&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;janedoe@example.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="s"&gt;StorageAccountBytesMax&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@waitFor&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;@evaluate&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="s"&gt;billabe_buy&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Calculating...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertSelectorHasText&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="s"&gt;billabe_buy&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;45.00&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;10gb is 45.00 euros for janedoe&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# unowned invoice: prohibit&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/invoices/view/201100493&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertTextExists&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Invoice not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;prohibit access to invoice of another customer&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# owned invoice: allow and check it&amp;#39;s price is 12 cents&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thenOpen&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;https://&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;testhost&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/invoices/view/201100975&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertTextExists&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Subtotal&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;my invoice has a subtotal&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertEval&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;td.total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;invoice 201100975 total is 12 cents&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;## Bombs away&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cm"&gt;########################################################################&lt;/span&gt;&lt;span class="c1"&gt;##&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;@test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderResults&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;See what we did? In just ~100 LoC we make sure this app deals correct prices for
new products, protects people&amp;#8217;s invoices and admin pages from unauthorized access, makes sure
the login system functions &amp;amp; redirects correctly, and that no page except &lt;code&gt;/nonexistent&lt;/code&gt;
has any errors on it.
If any of these conditions aren&amp;#8217;t met, a screenshot is made.&lt;/p&gt;

&lt;h3&gt;Run&lt;/h3&gt;

&lt;p&gt;To run it, type something like:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;casperjs &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  ./tests/project.coffee &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --ignore-ssl-errors&lt;span class="o"&gt;=&lt;/span&gt;yes &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --testhost&lt;span class="o"&gt;=&lt;/span&gt;staging.exampleproject.com &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  --screenfile&lt;span class="o"&gt;=&lt;/span&gt;./webroot/fails/screenshot.png &lt;span class="c"&gt;# || script to upload screenshot.png to campfire.&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Ideally, you&amp;#8217;d wrap this up in a script and plug it into your
&lt;a href="http://en.wikipedia.org/wiki/Continuous_integration"&gt;Continuous Integration&lt;/a&gt; server
so that it gets run on every change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alternatively&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While still developing, it&amp;#8217;s really pleasant to have your Mac open the screenshot
automatically after any fail:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rm -f ~/Desktop/screen.png &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt; ; casperjs &lt;span class="nb"&gt;test&lt;/span&gt; ./tests/main.coffee --ignore-ssl-errors&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; --testhost&lt;span class="o"&gt;=&lt;/span&gt;www.example.local --screenfile&lt;span class="o"&gt;=&lt;/span&gt;~/Desktop/screen.png &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;||&lt;/span&gt; open ~/Desktop/screen.png
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There are also paid services you can outsource this to. Most of them offer a lot more
features such as also testing against FF, IE, Opera, Mobile, etc. so it may
make sense for you to use one of those. Some I know in no particular order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://saucelabs.com/"&gt;Sauce Labs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://browserling.com/"&gt;Browserling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.browserstack.com/"&gt;BrowserStack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;As for some advantages of rolling this out yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;customize to your needs, run on your own CI server&lt;/li&gt;
&lt;li&gt;the tests &amp;amp; actual code are stored in the same repository, hack on your code, hack on your tests, it&amp;#8217;s all versioned and coupled, this makes it easy and fun to update your tests.&lt;/li&gt;
&lt;li&gt;no monthly fees&lt;/li&gt;
&lt;li&gt;and as you&amp;#8217;ve noticed it&amp;#8217;s actually not hard to do anymore, thanks to PhantomJS &amp;amp; CasperJS&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/A-nulBr6k10" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2012/11/03/highlevel-testing-with-casperjs/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Reverse a Multibyte String in PHP]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/Drzl08Q083M/" />
    <updated>2012-10-09T13:07:00+02:00</updated>
    <id>http://kvz.io/blog/2012/10/09/reverse-a-multibyte-string-in-php</id>
    <content type="html">&lt;p&gt;PHP&amp;#8217;s &lt;a href="http://php.net/manual/en/function.strrev.php"&gt;strrev&lt;/a&gt;
is not safe to use on utf-8 strings because it reverses a string
one byte at a time. So if a character consists of multiple bytes it cannot be preserved
as an entity in the reversed result.&lt;/p&gt;

&lt;p&gt;There is no &lt;a href="http://php.net/manual/en/book.mbstring.php"&gt;Multibyte String&lt;/a&gt; alternative
to &lt;code&gt;strrev&lt;/code&gt; either.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;We did some googling, but strangely enough all solutions we encountered were
either invalid or incredibly heavy memory/code wise.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/a/4919626/151666"&gt;using utf8_decode&lt;/a&gt; only works if your characters in the string exist in the ISO-8859-1 character set&lt;/li&gt;
&lt;li&gt;&lt;a href="http://php.net/manual/en/function.strrev.php#83461"&gt;using preg_match_all&lt;/a&gt; seems weirdly over-engineered&lt;/li&gt;
&lt;li&gt;&lt;a href="http://php.net/manual/en/function.strrev.php#62422"&gt;a simpler preg_match_all&lt;/a&gt; works, but on a 2MB string PHP was already using 150MB of memory. This is actually what sparked our search when
when &lt;a href="https://twitter.com/renan_saddam"&gt;@renan_saddam&lt;/a&gt; noticed his
&lt;a href="https://github.com/renansaddam/email_reply_parser/blob/9c2610fbec87211591701ec322723129ae4a1768/library/EmailReplyParser/Fragment.php#L82"&gt;PHP port&lt;/a&gt; of Github&amp;#8217;s &lt;a href="https://github.com/github/email_reply_parser"&gt;email_reply_parser&lt;/a&gt; choked on a 2MB multibyte email.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;What we came up with&lt;/h2&gt;

&lt;p&gt;Is dead simple, but I&amp;#8217;m putting it online anyway since it&amp;#8217;s apparently not common good.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt; (mb_strrev.php)&lt;/span&gt; &lt;a href='http://kvz.io/downloads/code/mb_strrev.php'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mb_strrev&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$encoding&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nv"&gt;$encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;mb_detect_encoding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;$length&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;mb_strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$encoding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;$reversed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$length&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nv"&gt;$reversed&lt;/span&gt; &lt;span class="o"&gt;.=&lt;/span&gt; &lt;span class="nb"&gt;mb_substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$encoding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$reversed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Example:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;echo&lt;/span&gt;    &lt;span class="nb"&gt;strrev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Gonçalves&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// returns sevla??noG&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nx"&gt;mb_strrev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Gonçalves&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// returns sevlaçnoG&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In our tests, the above function was &lt;strong&gt;factor 5x&lt;/strong&gt; more efficient in regards to memory consumption than the &lt;code&gt;preg_match_all&lt;/code&gt; solution.&lt;/p&gt;

&lt;p&gt;Hope this helps&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/Drzl08Q083M" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2012/10/09/reverse-a-multibyte-string-in-php/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Quick server debugging with WTF]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/6VTG8Zg6UW8/" />
    <updated>2012-10-03T16:30:00+02:00</updated>
    <id>http://kvz.io/blog/2012/10/03/quick-server-debugging-with-wtf</id>
    <content type="html">&lt;p&gt;If something weird is happening, you want to know everything that&amp;#8217;s going on
on a server, as fast as possible.&lt;/p&gt;

&lt;p&gt;At these times, you will be very happy to have a simple alias &lt;code&gt;wtf&lt;/code&gt; installed
that you can type immediately after logging into a server, and see
all that it&amp;#8217;s busy with.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h2&gt;tldr; oneliner (okay, three-liner)&lt;/h2&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;$(fgrep &amp;#39;alias wtf&amp;#39; ~/.bash_aliases)&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;alias wtf=&amp;#39;tail -f /var/log/{dmesg,messages,*{,/*}{log,err}}&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &amp;gt;&amp;gt; ~/.bash_aliases &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; . ~/.bash_aliases
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Explained&lt;/h2&gt;

&lt;p&gt;Normally you could type&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tail -f /var/log/messages
&lt;/span&gt;&lt;span class='line'&gt;tail -f /var/log/syslog
&lt;/span&gt;&lt;span class='line'&gt;tail -f /var/log/mysql/error.log
&lt;/span&gt;&lt;span class='line'&gt;tail -f /var/log/nginx/php-errors.log
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#etc&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;But you can have all this goodness in one command:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tail -f /var/log/&lt;span class="o"&gt;{&lt;/span&gt;dmesg,messages,*&lt;span class="o"&gt;{&lt;/span&gt;,/*&lt;span class="o"&gt;}{&lt;/span&gt;log,err&lt;span class="o"&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now this is slightly hard to type, so we&amp;#8217;ll save it in an alias:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;wtf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;[...]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Cool. You can now just type &lt;code&gt;wtf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However next time you login, the alias is lost. To make it persist, we store it
in your &lt;code&gt;~/.bash_aliases&lt;/code&gt;. This file gets sourced everytime you log into bash
(if you use zsh, you will know what to do):&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;[...]&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bash_aliases
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;But this only stores the alias for your next logins. To make your current session
profit, we source it now:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;. ~/.bash_aliases
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;One more thing, you should just be able to copy paste this, without the alias getting
added twice, so we make sure it does not exist yet:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;$(fgrep &amp;#39;alias wtf&amp;#39; ~/.bash_aliases)&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(directly using &lt;code&gt;fgrep&lt;/code&gt; here could cause an &lt;code&gt;exit 1&lt;/code&gt; if &lt;code&gt;~/.bash_aliases&lt;/code&gt;
does not exist yet, in which case we still want to continue, so we check with &lt;code&gt;-z&lt;/code&gt; instead)&lt;/p&gt;

&lt;p&gt;And we put all this together as shown above in the oneliner, and we can start using &lt;code&gt;wtf&lt;/code&gt;
directly.&lt;/p&gt;

&lt;h2&gt;On a mac?&lt;/h2&gt;

&lt;p&gt;Add the following to your &lt;code&gt;~/.bash_profile&lt;/code&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f ~/.bash_aliases &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;. ~/.bash_aliases
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Courtesy of &lt;a href="https://twitter.com/dogmatic69/statuses/78102198432710656"&gt;@dogmatic and myself&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;: )&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/6VTG8Zg6UW8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2012/10/03/quick-server-debugging-with-wtf/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Blog with Octopress and Github pages]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/MJEZvk5fJPU/" />
    <updated>2012-09-25T15:08:00+02:00</updated>
    <id>http://kvz.io/blog/2012/09/25/blog-with-octopress</id>
    <content type="html">&lt;p&gt;This article aims to provide a compact tutorial for setting up an Octopress blog
from scratch on OSX.&lt;/p&gt;

&lt;p&gt;Since so many people encounter Mountain Lion breakage, the article starts with
a few pointers how to get Homebrew, Git, make, Ruby going first.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;Please look closely at the steps if you really want to do each of them.
For instance I replace &lt;code&gt;rvm&lt;/code&gt; with &lt;code&gt;rbenv&lt;/code&gt;, you may want to skip that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;kvz&lt;/code&gt; with your Github username everywhere.&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;kvz.io&lt;/code&gt; with your domain name everywhere.&lt;/li&gt;
&lt;li&gt;Replace &lt;a href="http://www.sublimetext.com/2"&gt;subl&lt;/a&gt; with your favorite editor everywhere such as &lt;a href="http://code.google.com/p/macvim/"&gt;mvim&lt;/a&gt;, &lt;a href="http://macromates.com/"&gt;mate&lt;/a&gt;, or &lt;a href="http://mouapp.com/"&gt;mou&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Upgraded to Mountain Lion?&lt;/h2&gt;

&lt;p&gt;Make sure you can build something again&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upgrade Xcode&lt;/li&gt;
&lt;li&gt;Launch Xcode&lt;/li&gt;
&lt;li&gt;Select Xcode -&gt; Preferences from the menu bar.&lt;/li&gt;
&lt;li&gt;Select the Downloads tab.&lt;/li&gt;
&lt;li&gt;Install &amp;#8220;Command Line Tools&amp;#8221;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&amp;#8220;Boots into OS X, and my terminal takes FOREVER to boot.
Fixing permissions on the /usr/local directory fixed most of that&amp;#8221;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo chown -R &lt;span class="sb"&gt;`&lt;/span&gt;whoami&lt;span class="sb"&gt;`&lt;/span&gt; /usr/local
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Fixing homebrew&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew update
&lt;/span&gt;&lt;span class='line'&gt;brew outdated|xargs brew install
&lt;/span&gt;&lt;span class='line'&gt;brew tap homebrew/dupes
&lt;/span&gt;&lt;span class='line'&gt;brew install apple-gcc42 git
&lt;/span&gt;&lt;span class='line'&gt;brew upgrade
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Switch from rvm to rbenv&lt;/h3&gt;

&lt;p&gt;Remove rvm&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rvm implode
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Install rbenv instead, and Ruby 1.9.3-p194 which is required for Octopress&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install rbenv
&lt;/span&gt;&lt;span class='line'&gt;brew install ruby-build
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(rbenv init -)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;rbenv install 1.9.3-p194
&lt;/span&gt;&lt;span class='line'&gt;rbenv global 1.9.3-p194
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Environment&lt;/h3&gt;

&lt;p&gt;This should be in your &lt;code&gt;~/.bash_profile&lt;/code&gt;, &lt;code&gt;~/.zshrc&lt;/code&gt; or &lt;code&gt;~/.zprofile&lt;/code&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$HOME/.rbenv/bin:$PATH&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(rbenv init -)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# required for https://github.com/imathis/octopress/issues/144&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LC_CTYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Source it now so you won&amp;#8217;t have to open another tab first&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zprofile &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; ~/.bash_profile
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Make sure you have no other Ruby versions in your &lt;code&gt;$PATH&lt;/code&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;# ${PATH}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# /Users/kevin/.rbenv/shims:/Users/kevin/.rbenv/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;e.g., mine had a legacy &lt;code&gt;/Users/kevin/.gem/ruby/1.8/bin&lt;/code&gt; in it, causing Jekyll to
segfault.&lt;/p&gt;

&lt;h2&gt;Installing Octopress as your blog&lt;/h2&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;git clone git://github.com/imathis/octopress.git kvz.io
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;kvz.io
&lt;/span&gt;&lt;span class='line'&gt;ruby --version &lt;span class="c"&gt;# should read ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin12.2.0]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;gem install bundler
&lt;/span&gt;&lt;span class='line'&gt;rbenv rehash
&lt;/span&gt;&lt;span class='line'&gt;bundle install
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Deploying to Github project pages (http://username.github.com/project[gh-pages])&lt;/h3&gt;

&lt;p&gt;Let octopress know about this&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rake setup_github_pages
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Repository url: git@github.com:kvz/kvz.io.git&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;rake install
&lt;/span&gt;&lt;span class='line'&gt;rake generate &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rake deploy
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Note: Different from Github use pages (http://username.github.com/username.github.com[master]).&lt;/p&gt;

&lt;p&gt;Setup a domain&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;kvz.io&amp;#39;&lt;/span&gt; &amp;gt; &lt;span class="nb"&gt;source&lt;/span&gt;/CNAME
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Put these DNS records in place&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;A     record from kvz.io     to 204.232.175.78  &lt;span class="o"&gt;(&lt;/span&gt;Cannot be a CNAME!&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;CNAME record from www.kvz.io to kvz.github.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Makefile&lt;/h3&gt;

&lt;p&gt;So you&amp;#8217;ll only have to type &lt;code&gt;make blog&lt;/code&gt; to push online ALL THE THINGS!&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;./Makefile&lt;/code&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt; (Makefile)&lt;/span&gt; &lt;a href='http://kvz.io/downloads/code/kvz.io/Makefile'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;all: tweets dependencies blog
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;setup:
&lt;/span&gt;&lt;span class='line'&gt;  rake setup_github_pages&lt;span class="se"&gt;\[&lt;/span&gt;git@github.com:kvz/kvz.io.git&lt;span class="se"&gt;\]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;unpub:
&lt;/span&gt;&lt;span class='line'&gt;  subl .
&lt;/span&gt;&lt;span class='line'&gt;  fgrep -rIi &lt;span class="s2"&gt;&amp;quot;published: false&amp;quot;&lt;/span&gt; ./source/_posts | awk -F: &lt;span class="s1"&gt;&amp;#39;{print &amp;quot;subl &amp;quot; $$1}&amp;#39;&lt;/span&gt; |bash
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;tweets:
&lt;/span&gt;&lt;span class='line'&gt;  rake twitter
&lt;/span&gt;&lt;span class='line'&gt;  make blog &lt;span class="nv"&gt;MSG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;updated twitter&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;comments:
&lt;/span&gt;&lt;span class='line'&gt;  rake build_comments
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;dependencies:
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace/kvz.io 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git clone git@github.com:kvz/kvz.io&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace/bash3boilerplate 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git clone git@github.com:kvz/bash3boilerplate.git&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace/kvzlib 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git clone git@github.com:kvz/kvzlib.git&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace/transloadit-api2 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git clone git@github.com:transloadit/transloadit-api2.git&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace/nsfailover 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/workspace &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git clone git@github.com:kvz/nsfailover&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;blog:
&lt;/span&gt;&lt;span class='line'&gt;  git pull &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  bundle install &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  rake integrate &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  rake build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  rake generate &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  rake deploy &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  git add .; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  git commit -am &lt;span class="s2"&gt;&amp;quot;blog update $$(date +%Y-%m-%d)&amp;quot;&lt;/span&gt;; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  git push origin master
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;.PHONY: blog%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Don’t forget to commit the source for your blog.&lt;/h3&gt;

&lt;p&gt;To add your project&amp;#8217;s master as the new origin. This is what
my  &lt;code&gt;.git/config&lt;/code&gt; looks like:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;core&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;repositoryformatversion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 0
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;filemode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;bare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;logallrefupdates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;ignorecase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;remote &lt;span class="s2"&gt;&amp;quot;origin&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; +refs/heads/*:refs/remotes/origin/*
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; git@github.com:kvz/kvz.io.git
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;remote &lt;span class="s2"&gt;&amp;quot;octopress&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; git://github.com/imathis/octopress.git
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; +refs/heads/*:refs/remotes/octopress/*
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;branch &lt;span class="s2"&gt;&amp;quot;master&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; origin
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;merge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; refs/heads/master
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This way you can pull from octopress/master to receive updates, and
push to origin/master to save your posts.&lt;/p&gt;

&lt;h2&gt;Start blogging&lt;/h2&gt;

&lt;p&gt;New article&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rake new_post&lt;span class="se"&gt;\[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Blog with Octopress&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;subl &lt;span class="nb"&gt;source&lt;/span&gt;/_posts/&lt;span class="k"&gt;$(&lt;/span&gt;date +%Y-%m-%d&lt;span class="k"&gt;)&lt;/span&gt;-blog-with-octopress.markdown
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;More&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://octopress.org/docs/configuring/"&gt;configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://octopress.org/docs/blogging/"&gt;basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://octopress.org/docs/blogging/code/"&gt;code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://octopress.org/docs/blogging/plugins/"&gt;plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/imathis/octopress/wiki/3rd-party-plugins"&gt;3rd party plugins&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Add an about page&lt;/h3&gt;

&lt;p&gt;Add &amp;amp; edit like so&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rake new_page&lt;span class="se"&gt;\[&lt;/span&gt;about&lt;span class="se"&gt;\]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;subl &lt;span class="nb"&gt;source&lt;/span&gt;/about/index.markdown
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Add a link to it in the navigation&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;subl &lt;span class="nb"&gt;source&lt;/span&gt;/_includes/custom/navigation.html
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Add an about panel&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;subl &lt;span class="nb"&gt;source&lt;/span&gt;/_includes/custom/asides/about.html
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;and now add it to your &lt;code&gt;_config.ym&lt;/code&gt; so it will be included on every page:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;default_asides&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;custom/asides/about.html&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;More &lt;a href="http://octopress.org/docs/blogging/"&gt;info&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Bombs away : )&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;make blog &lt;span class="nv"&gt;MSG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Updated blog&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Thanks&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://josediazgonzalez.com/2012/07/25/upgrading-from-lion-to-mountain-lion/"&gt;http://josediazgonzalez.com/2012/07/25/upgrading-from-lion-to-mountain-lion/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://octopress.org/docs/"&gt;http://octopress.org/docs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.moncefbelyamani.com/how-to-install-and-configure-octopress-on-a-mac/"&gt;http://www.moncefbelyamani.com/how-to-install-and-configure-octopress-on-a-mac/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.github.com/articles/user-organization-and-project-pages"&gt;https://help.github.com/articles/user-organization-and-project-pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Shopify/liquid/wiki"&gt;https://github.com/Shopify/liquid/wiki&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/MJEZvk5fJPU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2012/09/25/blog-with-octopress/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Revisiting Faster PHP Sessions]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/xJnsQ_M8sjE/" />
    <updated>2011-04-29T14:00:00+02:00</updated>
    <id>http://kvz.io/blog/2011/04/29/faster-php-sessions</id>
    <content type="html">&lt;blockquote&gt;&lt;p&gt;&amp;#8220;Simplicity is prerequisite for reliability.&amp;#8221;&lt;/p&gt;&lt;footer&gt;&lt;strong&gt;Edsger W. Dijkstra&lt;/strong&gt; &lt;cite&gt;&lt;a href='http://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD498.html'&gt;How Do We Tell Truths That Might Hurt?&lt;/a&gt;&lt;/cite&gt;&lt;/footer&gt;&lt;/blockquote&gt;


&lt;p&gt;As our experience grows, we learn from past mistakes and discover what&amp;#8217;s truely important in reliable systems.
When designing systems, simplicity is an often heard mantra, but it isn&amp;#8217;t getting applied nearly as much as spoken off. I&amp;#8217;m guilty of this too. I think it&amp;#8217;s mainly because engineers love to, well, engineer : ) and will naturally try to &lt;a href="http://teddziuba.com/2010/12/the-3-basic-tools-of-systems-engineering.html"&gt;outsmart problems by throwing more tech at it&lt;/a&gt;.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h2&gt;Article vs Article&lt;/h2&gt;

&lt;p&gt;In the light of this, I revisit my 2008 article &lt;a href="http://kvz.io/blog/2008/06/22/enhance-php-session-management/"&gt;Enhance PHP session management&lt;/a&gt;.
The article explains how you can use a central memcache server to store sessions for performance &amp;amp; scalability purposes.&lt;/p&gt;

&lt;p&gt;Having a shared something when you can avoid it is asking for problems, and I was just throwing unneeded tech at this: network protocols, pecl modules, configuration. All vulnerable to &lt;a href="http://pecl.php.net/bugs/search.php?cmd=display&amp;amp;package-name[]=memcache&amp;amp;status=All&amp;amp;search-for=&amp;amp;php-os=&amp;amp;boolean=0&amp;amp;author-email=&amp;amp;bug-type=&amp;amp;bug-age=0&amp;amp;bug-updated=0&amp;amp;order-by=id&amp;amp;direction=ASC&amp;amp;phpver=&amp;amp;limit=300&amp;amp;handle=&amp;amp;assign=&amp;amp;maintain=&amp;amp;begin=0"&gt;bugs&lt;/a&gt;, maintenance, performance penalties and outage.&lt;/p&gt;

&lt;p&gt;Using 2007 article &lt;a href="http://kvz.io/blog/2007/07/18/create-turbocharged-storage-using-tmpfs/"&gt;Create turbocharged storage using tmpfs&lt;/a&gt;, we can
defeat some of this over-engineering and take a simpler approach to speeding up sessions in PHP.
We&amp;#8217;ll store them decentralized in memory by mounting RAM onto the existing &lt;code&gt;/var/lib/php5&lt;/code&gt; session directories throughout your application servers, which I will call nodes from now on.&lt;/p&gt;

&lt;h2&gt;Make Session Dir Live in RAM&lt;/h2&gt;

&lt;p&gt;Add this to your &lt;code&gt;/etc/fstab&lt;/code&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Make PHP Sessions live in RAM&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;tmpfs /var/lib/php5 tmpfs &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;300M,atime 0 0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This will make sure the 300MB RAM device will be available on your next reboot as well.&lt;/p&gt;

&lt;p&gt;300MB is a lot.&lt;/p&gt;

&lt;p&gt;You can decrease it later on by changing the &lt;code&gt;/etc/fstab&lt;/code&gt; entry and&lt;/p&gt;

&lt;p&gt;executing &lt;code&gt;mount -o remount /var/lib/php5&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;Activate &amp;amp; Migrate Existing Sessions&lt;/h2&gt;

&lt;p&gt;Then execute:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Create a temporary place for current sessions&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;mkdir -p /tmp/phpsessions/
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Move current sessions to it&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;mv /var/lib/php5/* /tmp/phpsessions/
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Activate our ramdisk&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;mount -a
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Move the current sessions back&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;mv /tmp/phpsessions/* /var/lib/php5/
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Remove the temporary placeholder&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;rmdir /tmp/phpsessions
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Advantages&lt;/h2&gt;

&lt;p&gt;What&amp;#8217;s nice about saving sessions in a &lt;a href="http://kvz.io/blog/categories/tmpfs/"&gt;tmpfs&lt;/a&gt; device compared with saving in memcache is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you can migrate to this solution without logging people out : )&lt;/li&gt;
&lt;li&gt;nothing needs to be installed&lt;/li&gt;
&lt;li&gt;instead of throwing errors, it degrades gracefully as disk storage if implementation fails&lt;/li&gt;
&lt;li&gt;you can restart/flush/upgrade any existing memcache instances without people losing sessions&lt;/li&gt;
&lt;li&gt;it uses the default &lt;code&gt;/var/lib/php5&lt;/code&gt; directory, so no &lt;code&gt;.ini&lt;/code&gt; changes, and PHP&amp;#8217;s garbage collector will still purge old sessions&lt;/li&gt;
&lt;li&gt;it takes away a bottleneck &amp;amp; single point of failure in your architecture&lt;/li&gt;
&lt;li&gt;it&amp;#8217;s just a mountpoint, so existing monitoring tools will automatically trigger alerts when you need to allocate more space&lt;/li&gt;
&lt;li&gt;no locking issues with ajax calls (though I believe fixed in memcached-3.0.4beta)&lt;/li&gt;
&lt;li&gt;no protocol overhead&lt;/li&gt;
&lt;li&gt;less tech, so less prone to errors &amp;amp; bugs, easier upgrade process&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Decentralizing&lt;/h2&gt;

&lt;p&gt;Now this doesn&amp;#8217;t work in clusters without Sticky Sessions.
But you&amp;#8217;ve got to ask yourself: in huge clusters, do you really want Shared Sessions? The bigger the cluster, the more vulerable you&amp;#8217;ll become as
it really only adds a bottle-neck &amp;amp; single point of failure to your architecture.&lt;/p&gt;

&lt;p&gt;With decent loadbalancers like EC2&amp;#8217;s ELB, Pound, HAProxy it becomes childsplay to implement Sticky Sessions so that people keep ending up on the node that has their session.&lt;/p&gt;

&lt;p&gt;When you&amp;#8217;re &lt;a href="http://www.codinghorror.com/blog/2011/04/working-with-the-chaos-monkey.html"&gt;designing to tolerate failure&lt;/a&gt;, this architecture
is much more robust than depending on anything shared.&lt;/p&gt;

&lt;p&gt;Yes, some people will be logged out when you shut down a node (vs &lt;em&gt;all&lt;/em&gt; when your session store goes down).&lt;/p&gt;

&lt;p&gt;To counter you could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;drain a node&amp;#8217;s connections before you take it into planned maintenance, this way nobody is affected&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kvz.io/blog/2007/08/16/synchronize-files-with-rsync/"&gt;rsync&lt;/a&gt; sessions between nodes if it&amp;#8217;s crucial that all sessions survive outage.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This could even be automated where nodes can cover for eachother.
If it&amp;#8217;s worth the investment depends on your application. Are your nodes likely to go down completely? How many customers will get logged out? What kind of data is lost?&lt;/p&gt;

&lt;p&gt;Even if your session store is clustered and uses persistent storage like
&lt;a href="http://kvz.io/blog/2010/03/25/redis-in-php/"&gt;Redis&lt;/a&gt; or
&lt;a href="http://kvz.io/blog/categories/mysql/"&gt;MySQL&lt;/a&gt;
(not the right tool for the job people): network outage, maintenance and misconfiguration can hurt you badly, logging out all customers or worse, throwing errors throughout your platform.&lt;/p&gt;

&lt;p&gt;Problems will be bigger and harder to solve.&lt;/p&gt;

&lt;p&gt;Whereas if the RAM mountpoint fails, &lt;code&gt;/var/lib/php5&lt;/code&gt; just degrades gracefully as normal disk-based storage. Making sessions slower on that 1 node, but at you&amp;#8217;ll still be serving customers.&lt;/p&gt;

&lt;p&gt;I welcome your thoughts on this!&lt;/p&gt;

&lt;!-- Generated by Rakefile:build --&gt;


&lt;h3&gt;Imported comments&lt;/h3&gt;

&lt;p&gt;These were imported from my old blog. Please use disqus below for new comments&lt;/p&gt;

&lt;div style="padding: 3px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; overflow-y: scroll; max-height: 500px;"&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.hotcooktops.com" rel="nofollow"&gt;Guadalupe&lt;/a&gt;
&lt;/strong&gt;
on 2012-04-12 04:51:41 &lt;br /&gt;
Thank you for the auspicious writeup. It in fact was a amusement account it.&lt;br /&gt;
Look advanced to far added agreeable from &lt;br /&gt;
you! However, how can we communicate?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.mind-zap.com" rel="nofollow"&gt;mindzap&lt;/a&gt;
&lt;/strong&gt;
on 2012-04-04 13:39:34 &lt;br /&gt;
Its possible now to rank no.1 on all search engine with our unique white hats SEO techniques. Rank on the top and get maximum traffic which means maximum sales.Make your site popular online with our seo services, search engine optimization, link building, social media marketing services. High search engine rank assured.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.coachhandbagspursesoutlet.com" rel="nofollow"&gt;Coach Bags&lt;/a&gt;
&lt;/strong&gt;
on 2012-03-01 08:16:25 &lt;br /&gt;
How&amp;#8217;s it going? I enjoyed reading through this publish. My husband and I have been researching for this kind of article with the longest time and We know that your details about the issue at hand is spot on. I&amp;#8217;ll be certain to introduce this posting to my neice. Can you tell me how to acquire your new RSS feed? Continue to keep on blogging!&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Maciej Lisiewski
&lt;/strong&gt;
on 2011-12-31 08:10:35 &lt;br /&gt;
Sessions in ramfs is a very, very bad idea.&lt;br /&gt;
&lt;br /&gt;
1. The obvious: when the machine crashes all sessions are lost. While sometimes that is acceptable it&amp;#8217;s a definite no-go for ecommerce sites that share session id with cart id (common practice to reduce number of cookies).&lt;br /&gt;
&lt;br /&gt;
2. Limited (compared to other storage solutions) capacity. With small sessions you&amp;#8217;ll end up with a 1-4 KB session files. That means that 300MB you are using allows 75-300k concurrent sessions. Seems a lot til you remember that webcrawlers from Google, Yahoo, Bing, etc don&amp;#8217;t use cookies and each request equals new session. With a large website number of requests in millions per day is not uncommon. Boom, suddenly no new session can be created, 502.&lt;br /&gt;
&lt;br /&gt;
3. As with any file storage you loose all the benefits of storing sessions in relational database - the most basic being an ability to modify session of a specific user (log him out for example) - this way you can actually store permissions in session and avoid querying permissions per request.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I went for a hybrid solution:&lt;br /&gt;
- sessions are stored both in database and key-store (APC/memcached/whatever I plug in depending on site size)&lt;br /&gt;
- database is checked only if key-store returns no match - if there is a match in db it&amp;#8217;s copied to key-store.&lt;br /&gt;
- database is written to only if session value is modified or if time since last persistent (db) store is longer than predefined interval&lt;br /&gt;
- most popular/aggressive crawlers are matched by user agent and no session is created for them&lt;br /&gt;
&lt;br /&gt;
Result is fast. Not as fast as tmpfs, but close enough and it supports sharding out of the box (add modulo of request id to select memcached and/or db shard and you&amp;#8217;re done) without the need to sync files. No fancy clusters - just add new box if you need it and change divisor in config.&lt;br /&gt;
Garbage collection is dead simple - cron job that deletes entries from db that had no persistent store for predefined interval - key-store expires on it&amp;#8217;s own.&lt;br /&gt;
You can kill any memcached instance - new one will load all the sessions from db (there will be a load spike, but each will be read just once).&lt;br /&gt;
It degrades gracefully if at least db works. If it doesn&amp;#8217;t you&amp;#8217;re fucked anyway ;-)&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.winwinhost.com/" rel="nofollow"&gt;webhoster&lt;/a&gt;
&lt;/strong&gt;
on 2011-12-30 05:36:51 &lt;br /&gt;
You got a point about load balancers. At least for the presentation layer.&lt;br /&gt;
&lt;br /&gt;
Still might need to cluster a central data layer.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://janakporwal.com" rel="nofollow"&gt;Janak&lt;/a&gt;
&lt;/strong&gt;
on 2011-12-01 11:47:42 &lt;br /&gt;
AWESOME! Instant, noticeable improvement. And super useful for me as I have some servers with pretty slow Disk I/O.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
bird
&lt;/strong&gt;
on 2011-11-30 08:46:27 &lt;br /&gt;
nice work&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Mike
&lt;/strong&gt;
on 2011-11-01 15:56:10 &lt;br /&gt;
Well now, sticky sessions are a big nono, since those will hinder your very purpose for using a cluster.&lt;br /&gt;
&lt;br /&gt;
If I have 3 servers, and I use sticky sessions and I do have a flash flood, I would get:&lt;br /&gt;
- webserver1 - 10% load&lt;br /&gt;
- webserver2 - 150% load&lt;br /&gt;
- webserver3 - 40% load&lt;br /&gt;
instead of using all three in an even way.&lt;br /&gt;
&lt;br /&gt;
Maybe sticky would be nice for 10-20+ servers in a cluster, numbers that would led the statistics work and assure an almost even distribution.&lt;br /&gt;
&lt;br /&gt;
But having inbalance in an small cluster is like not having the cluster at all. We do LB for performance _and_ failover not only for failover.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
David
&lt;/strong&gt;
on 2011-08-25 18:17:09 &lt;br /&gt;
Hi,&lt;br /&gt;
&lt;br /&gt;
I implemented this as we had a lot of issues with session_start taking up to 3 seconds, just because of opening files, and our page loads decreased drastically!&lt;br /&gt;
&lt;br /&gt;
Since this was an absolutely fantastic result, we decided to save our cached objects (which were now cached into a database), in ram as well&amp;#8230;  translations are now saved in a serialized array into ram, and still has a copy in the database.&lt;br /&gt;
&lt;br /&gt;
page loads for some of our larger pages went from 7 seconds to &amp;
lt;0.3 seconds.&lt;br /&gt;
&lt;br /&gt;
So yes - our profiling shows that this is a GREAT result.  - we just put in 4 GIGS of additional RAM, and off we go!&lt;br /&gt;
&lt;br /&gt;
Thanks for a great post!  This absolutely saves our day, and helps us maintain good structured code, as we didn&amp;#8217;t want to start compromising by taking shortcuts in our code &amp;
quot;just for performance reasons&amp;
quot;, as we see happen so many times, unfortunately.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.mrclay.org/" rel="nofollow"&gt;Steve Clay&lt;/a&gt;
&lt;/strong&gt;
on 2011-05-11 16:57:47 &lt;br /&gt;
Does any storage over 300M roll over to disk like &amp;
quot;virtual memory&amp;
quot;? If not, how do you handle too many/too big session files?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.keboola.com" rel="nofollow"&gt;Ondra&lt;/a&gt;
&lt;/strong&gt;
on 2011-05-09 10:55:41 &lt;br /&gt;
We have a more techy solution - db with memcached. &lt;br /&gt;
&lt;br /&gt;
http://www.keboola.com/blog/php-sessions-with-memcached-and-a-database-session-in-the-cloud-done-right/&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Coret
&lt;/strong&gt;
on 2011-05-07 12:24:25 &lt;br /&gt;
When I tried to move my session store to the newly created tmpfs it ran out of space (inodes). To counter this I added &amp;
quot;nr_inodes=400k&amp;
quot; to the fstab entry.&lt;br /&gt;
&lt;br /&gt;
Also, try to specify a good mode, so your webserver can read/write session files (something like mode=777 in your fstab entry, or less for more security).&lt;br /&gt;
&lt;br /&gt;
First impression: the i/o wait on my server is significantly down!&lt;br /&gt;
&lt;br /&gt;
Question: I use &amp;
quot;3;/var/lib/php5&amp;
quot; as session.save_path, so there&amp;#8217;s a directory structure of 3 levels deep. When my server is rebooted now, this directory structure has to be regenerated&amp;#8230; Should I just abandon this approach and just use 1 directory with 235K files?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://mostlygeek.com" rel="nofollow"&gt;Ben Wong&lt;/a&gt;
&lt;/strong&gt;
on 2011-05-06 00:16:32 &lt;br /&gt;
Interesting idea. I&amp;#8217;d like to see some benchmarks of the performance of this vs straight up disk access sessions. &lt;br /&gt;
&lt;br /&gt;
I&amp;#8217;d be surprised if there is a huge performance improvement over regular disk based sessions. Unless you&amp;#8217;re on something like Amazon&amp;#8217;s ELB which isn&amp;#8217;t a real disk anyways. &lt;br /&gt;
&lt;br /&gt;
A technique that I&amp;#8217;m doing is using signed data in cookies as a session storage technique. &lt;br /&gt;
&lt;br /&gt;
Pros: &lt;br /&gt;
&lt;br /&gt;
1. no server side state&lt;br /&gt;
2. no disk access to check&lt;br /&gt;
3. No locking&lt;br /&gt;
&lt;br /&gt;
Cons: &lt;br /&gt;
&lt;br /&gt;
1. bigger cookies (but still &amp;
lt; 100 bytes)&lt;br /&gt;
2. no server side invalidation of a session w/out some server side state. We use memcache for this, but in a simple, does this key exists? Ok cookie is valid. &lt;br /&gt;
&lt;br /&gt;
For the application I&amp;#8217;m working on we&amp;#8217;ll be seeing hundreds of req/second and keeping less state makes scaling out a lot easier. &lt;br /&gt;
&lt;br /&gt;
Also each user is sending requests concurrently so locking *all* requests until the current one finishes really slows down performance. Instead, to prevent race conditions on data we let the database do atomic operations and always code knowing that data could have changed from the time you read to the time to write back to the db. Compare/Swap patterns are great here.&lt;br /&gt;
&lt;br /&gt;
For security, so users can&amp;#8217;t forge their own cookies we: &lt;br /&gt;
&lt;br /&gt;
a) sign them w/ sha1&lt;br /&gt;
b) expire them with a timestamp (int, embedded into data)&lt;br /&gt;
&lt;br /&gt;
When the cookie comes in, we validate the data (json serialized), the signature and that the cookie has not expired. &lt;br /&gt;
&lt;br /&gt;
If everything is OK we process the request and issue a *new* cookie.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.phally.com" rel="nofollow"&gt;Frank de Graaf&lt;/a&gt;
&lt;/strong&gt;
on 2011-05-05 14:24:46 &lt;br /&gt;
This is a great idea. What I like most is that you get rid of the dependencies of other applications and that you don&amp;#8217;t have to change your ini settings for it. As you said, it would make it easier to maintain and to migrate. Excellent article, cheers.&lt;br/&gt;
&lt;/p&gt;
&lt;/div&gt;



&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/xJnsQ_M8sjE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2011/04/29/faster-php-sessions/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Revisiting Spaces and Tabs]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/RSrnHOo4ayU/" />
    <updated>2011-03-31T14:00:00+02:00</updated>
    <id>http://kvz.io/blog/2011/03/31/spaces-vs-tabs</id>
    <content type="html">&lt;p&gt;This article in 50 words: I used to prefer spaces vs tabs, now I don&amp;#8217;t care so much, think it&amp;#8217;s
more important that you can easily switch on a per-project basis. Have some thoughts on how conventions
should be established, and I&amp;#8217;ll demonstrate bash code that can convert your codebase to a new standard.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h2&gt;Back in the day&lt;/h2&gt;

&lt;p&gt;I used to prefer &lt;a href="http://www.jwz.org/doc/tabs-vs-spaces.html"&gt;spaces over tabs&lt;/a&gt; so
code would look consistent throughout the monospace universe. No matter what crappy
viewer people ended up using on it: as long as it supported a monospace font,
your code looked as intended.
I also did some work for &lt;a href="http://pear.php.net/package/System-Daemon"&gt;PEAR&lt;/a&gt;
and they enforced spaces in their thorough &lt;a href="http://pear.php.net/manual/en/standards.php"&gt;Coding Standards&lt;/a&gt;.
Which was later adopted by many frameworks, sometimes with small deviations.&lt;/p&gt;

&lt;h2&gt;Quest for the holy Convention&lt;/h2&gt;

&lt;p&gt;After years of spaces in my code I started using CakePHP and their standard was tabs.
Nothing to get hung up over, but after a while my code started intermingling with other Cake
developer&amp;#8217;s code and that&amp;#8217;s when it gets a little
&lt;a href="http://github.com/kvz/cakephp-rest-plugin/blob/40fbe802d3d9eb526efb71eaa101efc3d6b82090/controllers/components/rest.php#L681"&gt;hairy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I started using tabs there cause in my view conventions are much like traffic rules as I mentioned before in
&lt;a href="http://kvz.io/blog/2009/03/04/sql-formatting/"&gt;SQL Formatting&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
  
It&amp;#8217;s irrelevant if people drive on the right or left side of the road,
  as long as they do the same  
&lt;/blockquote&gt;


&lt;p&gt;At &lt;a href="http://transloadit.com"&gt;Transloadit&lt;/a&gt; we started using 2 spaces for JavaScript as it&amp;#8217;s
&lt;a href="http://nodeguide.com/style.html#tabs-vs-spaces"&gt;the way of node.js&lt;/a&gt;.
And then there&amp;#8217;s a little Ruby project I started hacking on and they also like 2 spaces.&lt;/p&gt;

&lt;h2&gt;Adopt many Conventions&lt;/h2&gt;

&lt;p&gt;Coding standards change. Within a project, organization, framework, and even language.
Or they change for you simply because you contribute to different aforementioned forms.&lt;/p&gt;

&lt;p&gt;Instead of trying to enforce one preference throughout all of my projects, I
adopt the rules of the domain at hand. In this order:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;Project &amp;gt; Organization &amp;gt; Framework &amp;gt; Language
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;(where conflicting, left wins from right)&lt;/p&gt;

&lt;p&gt;On a side-note, I think it&amp;#8217;s the convention-designer&amp;#8217;s responsibility to align his conventions with
the &lt;em&gt;layer they&amp;#8217;re building on&lt;/em&gt; as much as possible. So frameworks should look at their language.
companies should look at their framework. This makes for consistently looking codebases.
And that helps encouraging involvement. Nobody likes messing with code that suffers from poor housekeeping.&lt;/p&gt;

&lt;p&gt;In order to be flexible about this, it helps a lot if your IDE supports per-project settings
(I currently use both &lt;a href="http://kvz.io/blog/2008/12/02/my-new-ide-netbeans/"&gt;NetBeans&lt;/a&gt;
&amp;amp; &lt;a href="http://kvz.io/blog/2010/11/30/learning-vim/"&gt;Vim&lt;/a&gt;, and they do an fine job at that).
In NetBeans it&amp;#8217;s easy to mess up though cause it&amp;#8217;s pretty much indentation agnostic. So sometimes you
won&amp;#8217;t notice you&amp;#8217;re filling a 4-spaces file with tabs, ruining the code in other views/editors.&lt;/p&gt;

&lt;p&gt;Once that happens, or maybe if you&amp;#8217;re porting big chunks of &amp;#8216;legacy&amp;#8217; code to a new
standard that&amp;#8217;s closer to your &lt;em&gt;layer&lt;/em&gt;, you&amp;#8217;ll need decent conversion scripts.&lt;/p&gt;

&lt;h2&gt;Switch Conventions&lt;/h2&gt;

&lt;p&gt;There are many pages on converting spaces to tabs on Linux or Mac,
but I wasn&amp;#8217;t satisfied as they:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Also change non-leading whitespace (which may not be what you want, e.g. a tab-indented document could still &lt;a href="http://pear.php.net/manual/en/standards.funcalls.php"&gt;use spaces to promote readability around assignments&lt;/a&gt;,
or inside big strings)&lt;/li&gt;
&lt;li&gt;Don&amp;#8217;t support multiple levels of indention&lt;/li&gt;
&lt;li&gt;Can&amp;#8217;t be run from command-line (e.g. depend on IDE)&lt;/li&gt;
&lt;li&gt;Are specific to a language (&lt;code&gt;indent&lt;/code&gt; / &lt;code&gt;astyle&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Messed up my indentation (&lt;code&gt;expand&lt;/code&gt; / &lt;code&gt;unexpand&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In an attempt to come up with a reliable tabs vs spaces converter that you
can simply run inside a directory and will traverse your source files, I&amp;#8217;d like to share a couple
of lines of BASH.&lt;/p&gt;

&lt;h3&gt;Warnings:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only do this when your source is under version control, these snippets make no backups!
So execute, test, verify, commit. Or hit &lt;code&gt;git reset --hard&lt;/code&gt; if you don&amp;#8217;t like it (leave a comment for improvement!)&lt;/li&gt;
&lt;li&gt;Currently processes &lt;code&gt;.php&lt;/code&gt;, &lt;code&gt;.ctp&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.css&lt;/code&gt;, &lt;code&gt;.sh&lt;/code&gt;. But can easily be modified to do other extensions as well.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Ubuntu&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# 4 Spaces to tabs&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P  . -type f -regextype egrep -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp|js|css|sh)$&amp;#39;&lt;/span&gt; -print0 | xargs -0  sed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;:repeat; s/^\(\t*\)    /\1\t/; t repeat&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Strip any trailing whitespace&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P  . -type f -regextype egrep -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp|js|css|sh)$&amp;#39;&lt;/span&gt; -print0 | xargs -0  sed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;s/[[:blank:]]*$//g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Strip any trailing blank lines (http://www.eng.cam.ac.uk/help/tpl/unix/sed.html)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P  . -type f -regextype egrep -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp|js|css|sh)$&amp;#39;&lt;/span&gt; -print0 | xargs -0  sed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e :a -e &lt;span class="s1"&gt;&amp;#39;/^\n*$/{$d;N;ba&amp;#39;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Strip any trailing PHP closing tags&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P  . -type f -regextype egrep -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp)$&amp;#39;&lt;/span&gt; -print0 | xargs -0 sed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e :a -e &lt;span class="s1"&gt;&amp;#39;/^&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s1"&gt;*$/{$d;N;ba&amp;#39;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Check the PHP files for syntax errors&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P  . -type f -regextype egrep -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp)$&amp;#39;&lt;/span&gt; -exec php -l &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &amp;gt; /dev/null
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;Mac&lt;/h3&gt;

&lt;p&gt;On a Mac? You need GNU sed! - Read below.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# 4 spaces to tabs&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P -E . -type f -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp|js|css|sh)$&amp;#39;&lt;/span&gt; -print0 | xargs -0 gsed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;:repeat; s/^\(\t*\)    /\1\t/; t repeat&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# tabs to 2 spaces&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P -E . -type f -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp|js|css|sh)$&amp;#39;&lt;/span&gt; -print0 | xargs -0 gsed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;:repeat; s/^\(\(  \)*\)\t/\1  /; t repeat&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Strip any trailing whitespace&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P -E . -type f -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp|js|css|sh)$&amp;#39;&lt;/span&gt; -print0 | xargs -0 gsed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;s/[[:blank:]]*$//g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Strip any trailing blank lines (http://www.eng.cam.ac.uk/help/tpl/unix/sed.html)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P -E . -type f -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp|js|css|sh)$&amp;#39;&lt;/span&gt; -print0 | xargs -0 gsed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e :a -e &lt;span class="s1"&gt;&amp;#39;/^\n*$/{$d;N;ba&amp;#39;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Strip any trailing PHP closing tags&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P -E . -type f -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp)$&amp;#39;&lt;/span&gt; -print0 | xargs -0 gsed -i&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; -e :a -e &lt;span class="s1"&gt;&amp;#39;/^&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s1"&gt;*$/{$d;N;ba&amp;#39;&lt;/span&gt; -e &lt;span class="s1"&gt;&amp;#39;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# extra: Check the PHP files for syntax errors&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find -P -E . -type f -regex &lt;span class="s1"&gt;&amp;#39;.*\.(php|ctp)$&amp;#39;&lt;/span&gt; -exec php -l &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &amp;gt; /dev/null
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;Run into problems?&lt;/h3&gt;

&lt;p&gt;Please let me know, I&amp;#8217;ll update the article so that these lines become the perfect converters.&lt;/p&gt;

&lt;h2&gt;On a Mac? You need gnu-sed&lt;/h2&gt;

&lt;p&gt;Mac OSX (BSD) has a cripled &lt;code&gt;sed&lt;/code&gt;.
This &lt;a href="http://muzso.hu/2008/08/24/sed-in-darwin-leopard-is-crippled-in-many-ways"&gt;illustrates&lt;/a&gt; my point:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# On Mac:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1|2|||5||7|&amp;quot;&lt;/span&gt; | sed -e &lt;span class="s1"&gt;&amp;#39;: repeat; s/||/|NULL|/; t repeat&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;1|2|||5||7|
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# On Linux:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1|2|||5||7|&amp;quot;&lt;/span&gt; | sed -e &lt;span class="s1"&gt;&amp;#39;: repeat; s/||/|NULL|/; t repeat&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;1|2|NULL|NULL|5|NULL|7|
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Luckily you can get GNU sed for Mac OSX just as well.
&lt;a href="http://github.com/mxcl/homebrew/wiki/installation"&gt;Get homebrew&lt;/a&gt;, then run:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install gnu-sed
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;And change all of &lt;code&gt;sed&lt;/code&gt; references to &lt;code&gt;gsed&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;That&amp;#8217;s it&lt;/h2&gt;

&lt;p&gt;How do you deal with changing coding standards?&lt;/p&gt;

&lt;!-- Generated by Rakefile:build --&gt;


&lt;h3&gt;Imported comments&lt;/h3&gt;

&lt;p&gt;These were imported from my old blog. Please use disqus below for new comments&lt;/p&gt;

&lt;div style="padding: 3px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; overflow-y: scroll; max-height: 500px;"&gt;
&lt;p&gt;
&lt;strong&gt;
Marc-André
&lt;/strong&gt;
on 2012-04-30 23:35:13 &lt;br /&gt;
Thanks. Very helpful to deal with my team who decided that tabs were better. Even for Ruby.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
b b
&lt;/strong&gt;
on 2011-11-29 06:08:06 &lt;br /&gt;
kjyg kjhgku uhgu&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://livestreaming-sports.com" rel="nofollow"&gt;sujon&lt;/a&gt;
&lt;/strong&gt;
on 2011-08-10 23:25:14 &lt;br /&gt;
Live sports on your pc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;
lt;a href=&amp;#8217;http://livestreaming-sports.com&amp;#8217;&amp;
gt;LIve streaming sports on your pc such as NFL, Rugby, soccer,NBA&amp;#8230;&amp;
lt;/a&amp;
gt;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://livestreaming-sports.com" rel="nofollow"&gt;sujon&lt;/a&gt;
&lt;/strong&gt;
on 2011-08-10 23:18:04 &lt;br /&gt;
IT is a good site for sports&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;
lt;a href=&amp;#8217;http://livestreaming-sports.com&amp;#8217;&amp;
gt;LIve streaming sports on your pc such as NFL, Rugby, soccer,NBA&amp;#8230;&amp;
lt;/a&amp;
gt;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://adult-adhd-treatment.blogspot.com" rel="nofollow"&gt;joe&lt;/a&gt;
&lt;/strong&gt;
on 2011-04-11 08:23:22 &lt;br /&gt;
nice info.thanks.&lt;br/&gt;
&lt;/p&gt;
&lt;/div&gt;



&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/RSrnHOo4ayU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2011/03/31/spaces-vs-tabs/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Optimize your Synology NAS for downloading]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/Q6jHBVUsRNw/" />
    <updated>2011-02-28T13:00:00+01:00</updated>
    <id>http://kvz.io/blog/2011/02/28/optimize-your-synology-for-downloading</id>
    <content type="html">&lt;p&gt;I recently bought a NAS so my data is safe &amp;amp; available, with the benefit of being low
power / noise / heat.
I&amp;#8217;ve considered Netgear, QNAP, but decided to go for a Synology
as it was affordable, still had a big community, decent reviews &amp;amp; Time Machine support.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;I wanted 4 bays so that I could use RAID5 and only lose 25% space on fault tolerance
instead of (RAID1) 50%. Synology has 2 offerings in the 4-bay home-user range this year:
the &lt;code&gt;DS411+&lt;/code&gt; (fast) and the &lt;code&gt;DS411j&lt;/code&gt; (slow).&lt;/p&gt;

&lt;p&gt;I figured as long as it can blast a bandwidth adequate for 1080p over my network,
I&amp;#8217;d save myself some money (300$ vs 600$), heat and power consumption that
come with the more powerful &lt;code&gt;+&lt;/code&gt; version.&lt;/p&gt;

&lt;p&gt;However now that it&amp;#8217;s here I want it do download from newsgroups and am running into
performance issues with my &lt;code&gt;j&lt;/code&gt;unior edition.&lt;/p&gt;

&lt;p&gt;No worries. With a little bit of hacking you can squeeze just enough performance
out of this thing to make sense of it all.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s how I turned my budget NAS that&amp;#8217;s mediocre at 8 things into a more powerful one
that&amp;#8217;s good at 3 things: downloading / file serving / backups.&lt;/p&gt;

&lt;h2&gt;Warning&lt;/h2&gt;

&lt;p&gt;This article assumes you&amp;#8217;re somewhat skilled in Linux. By applying these
suggestions you could seriously mess up your Disk Station.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m doing this on a &lt;code&gt;DS411j&lt;/code&gt; running DSM 3.0. Your mileage may vary.&lt;/p&gt;

&lt;h2&gt;Downloading&lt;/h2&gt;

&lt;p&gt;In &lt;a href="http://kvz.io/blog/2011/01/28/install-sabnzbd-on-your-synology/"&gt;an earlier article&lt;/a&gt; I
described how to install SABnzbd. After testdriving it for a while I was never able to
get it to download above 3MB/s (2 average). Where as &lt;code&gt;nzbget&lt;/code&gt; (the program used by Synology&amp;#8217;s
own Download Station), peaks at 8MB/s (6 average).&lt;/p&gt;

&lt;p&gt;Although I really like that SABnzbd automatically unpacks your downloads, these speed differences
made me decide to go back to nzbget. The &lt;code&gt;j&lt;/code&gt; is just not powerful enough to do SABnzbd at these
speeds, and I can write auto-unpackers myself.&lt;/p&gt;

&lt;h3&gt;Optimal Config&lt;/h3&gt;

&lt;p&gt;I found that optimal speeds can be reached by letting your Synology download with 8
connections on 1 single download. With these settings the load reaches 11, so don&amp;#8217;t
expect your NAS to do anything else while it&amp;#8217;s busy. But at least you&amp;#8217;re saturating
your connection.&lt;/p&gt;

&lt;p&gt;If you want it to multitask, limit it to 1 connection on 1 single download at any time,
but you won&amp;#8217;t see it peak beyond 2MB/s.&lt;/p&gt;

&lt;p&gt;If you use it for torrents as well, you don&amp;#8217;t want 1 slow torrent blocking the rest of
the queue. In that case, set it to 2 to 3 connections with 2 to 4 threads each for optimal downloading.&lt;/p&gt;

&lt;h2&gt;Turn off unused protocols&lt;/h2&gt;

&lt;p&gt;Decide on 1 file-sharing protocol (I chose Mac File service cause all my systems speak it
and use Time Machine, but SMB/Windows is typically the right choice).
Disable the rest in your configuration panel, saving a few precious MBs of RAM.&lt;/p&gt;

&lt;p&gt;This is all just done from your web-interface.&lt;/p&gt;

&lt;h2&gt;SSH access&lt;/h2&gt;

&lt;p&gt;Before you can do any hacking on your Synology, turn on SSH access in the web-interface&amp;#8217;s
control panel.
You can now type: &lt;code&gt;ssh root@&amp;lt;nas ip&amp;gt;&lt;/code&gt;. Followed by &lt;code&gt;sh&lt;/code&gt;. The root password is the same as
admin password.&lt;/p&gt;

&lt;h2&gt;AppStore : )&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://forum.synology.com/wiki/index.php/Overview-on-modifying-the-Synology-Server,-bootstrap,-ipkg-etc#How-to-install-ipkg"&gt;Get your hands on ipkg&lt;/a&gt;,
which is like your Synology&amp;#8217;s secret AppStore. From here on, it&amp;#8217;s much easier to install cool
additional software.&lt;/p&gt;

&lt;h2&gt;Turn off media indexers to free up CPU &amp;amp; Memory&lt;/h2&gt;

&lt;p&gt;When I logged in to see what was eating up my NAS&amp;#8217; resources, I saw a lot of processes running that I don&amp;#8217;t need
such as thumbnail generators and media indexers (&lt;code&gt;ffmpeg&lt;/code&gt; &amp;amp; &lt;code&gt;convert&lt;/code&gt;).
They were endlessly consuming 100% CPU, leaving nothing for my other tasks.&lt;/p&gt;

&lt;p&gt;Any currently available NAS is a terrible media streamer.
And that&amp;#8217;s ok, just get yourself an AC Ryan ($80) or Boxee Box ($250) to do that instead and
dedicate your NAS to less tasks.&lt;/p&gt;

&lt;p&gt;In my case that meant killing off all these wannabe media processes that are eating up your
poor handheld CPU with 128MB RAM (every MB we&amp;#8217;ll save from this point forward counts to faster
download speeds : )&lt;/p&gt;

&lt;p&gt;So if you don&amp;#8217;t use the Photo/Media/iTunes station and would like more power for other
tasks, consider turning off indexers:&lt;/p&gt;

&lt;p&gt;1) Turn off all services in the bottom configuration panel (iTunes, everything except
   Download Station, unless you&amp;#8217;re going to use
   &lt;a href="http://kvz.io/blog/2011/01/28/install-sabnzbd-on-your-synology/"&gt;SABnzbd&lt;/a&gt; for this)&lt;/p&gt;

&lt;p&gt;2) Login as root via SSH and stop all indexing:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;/usr/syno/etc/rc.d/S??synoindexd.sh stop
&lt;/span&gt;&lt;span class='line'&gt;/usr/syno/etc/rc.d/S??synomkflvd.sh stop
&lt;/span&gt;&lt;span class='line'&gt;/usr/syno/etc/rc.d/S??synomkthumbd.sh stop
&lt;/span&gt;&lt;span class='line'&gt;killall -9 convert
&lt;/span&gt;&lt;span class='line'&gt;killall -9 ffmpeg
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# If you don&amp;#39;t use Download Station (but e.g. SABnzbd instead):&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# /usr/syno/etc/rc.d/S??pgsql.sh stop&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;3) Make sure they won&amp;#8217;t restart on your next reboot.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;chmod -x /usr/syno/etc/rc.d/S??synoindexd.sh
&lt;/span&gt;&lt;span class='line'&gt;chmod -x /usr/syno/etc/rc.d/S??synomkflvd.sh
&lt;/span&gt;&lt;span class='line'&gt;chmod -x /usr/syno/etc/rc.d/S??synomkthumbd.sh
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# If you don&amp;#39;t use Download Station (but e.g. SABnzbd instead):&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# chmod -x /usr/syno/etc/rc.d/S??pgsql.sh&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Hint) After a DSM firmware upgrade, you need to repeat these steps.&lt;/p&gt;

&lt;h2&gt;Custom cleanup &amp;amp; rename script cause SAB is too slow&lt;/h2&gt;

&lt;p&gt;Building your own cleanup scripts can be fun (and risky).
If you want to get into it, you&amp;#8217;ll need some system tools at your disposal.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s what I cooked up to take care of my downloads:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt; (sabunpacker.sh)&lt;/span&gt; &lt;a href='http://kvz.io/downloads/code/sabunpacker.sh'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;span class='line-number'&gt;54&lt;/span&gt;
&lt;span class='line-number'&gt;55&lt;/span&gt;
&lt;span class='line-number'&gt;56&lt;/span&gt;
&lt;span class='line-number'&gt;57&lt;/span&gt;
&lt;span class='line-number'&gt;58&lt;/span&gt;
&lt;span class='line-number'&gt;59&lt;/span&gt;
&lt;span class='line-number'&gt;60&lt;/span&gt;
&lt;span class='line-number'&gt;61&lt;/span&gt;
&lt;span class='line-number'&gt;62&lt;/span&gt;
&lt;span class='line-number'&gt;63&lt;/span&gt;
&lt;span class='line-number'&gt;64&lt;/span&gt;
&lt;span class='line-number'&gt;65&lt;/span&gt;
&lt;span class='line-number'&gt;66&lt;/span&gt;
&lt;span class='line-number'&gt;67&lt;/span&gt;
&lt;span class='line-number'&gt;68&lt;/span&gt;
&lt;span class='line-number'&gt;69&lt;/span&gt;
&lt;span class='line-number'&gt;70&lt;/span&gt;
&lt;span class='line-number'&gt;71&lt;/span&gt;
&lt;span class='line-number'&gt;72&lt;/span&gt;
&lt;span class='line-number'&gt;73&lt;/span&gt;
&lt;span class='line-number'&gt;74&lt;/span&gt;
&lt;span class='line-number'&gt;75&lt;/span&gt;
&lt;span class='line-number'&gt;76&lt;/span&gt;
&lt;span class='line-number'&gt;77&lt;/span&gt;
&lt;span class='line-number'&gt;78&lt;/span&gt;
&lt;span class='line-number'&gt;79&lt;/span&gt;
&lt;span class='line-number'&gt;80&lt;/span&gt;
&lt;span class='line-number'&gt;81&lt;/span&gt;
&lt;span class='line-number'&gt;82&lt;/span&gt;
&lt;span class='line-number'&gt;83&lt;/span&gt;
&lt;span class='line-number'&gt;84&lt;/span&gt;
&lt;span class='line-number'&gt;85&lt;/span&gt;
&lt;span class='line-number'&gt;86&lt;/span&gt;
&lt;span class='line-number'&gt;87&lt;/span&gt;
&lt;span class='line-number'&gt;88&lt;/span&gt;
&lt;span class='line-number'&gt;89&lt;/span&gt;
&lt;span class='line-number'&gt;90&lt;/span&gt;
&lt;span class='line-number'&gt;91&lt;/span&gt;
&lt;span class='line-number'&gt;92&lt;/span&gt;
&lt;span class='line-number'&gt;93&lt;/span&gt;
&lt;span class='line-number'&gt;94&lt;/span&gt;
&lt;span class='line-number'&gt;95&lt;/span&gt;
&lt;span class='line-number'&gt;96&lt;/span&gt;
&lt;span class='line-number'&gt;97&lt;/span&gt;
&lt;span class='line-number'&gt;98&lt;/span&gt;
&lt;span class='line-number'&gt;99&lt;/span&gt;
&lt;span class='line-number'&gt;100&lt;/span&gt;
&lt;span class='line-number'&gt;101&lt;/span&gt;
&lt;span class='line-number'&gt;102&lt;/span&gt;
&lt;span class='line-number'&gt;103&lt;/span&gt;
&lt;span class='line-number'&gt;104&lt;/span&gt;
&lt;span class='line-number'&gt;105&lt;/span&gt;
&lt;span class='line-number'&gt;106&lt;/span&gt;
&lt;span class='line-number'&gt;107&lt;/span&gt;
&lt;span class='line-number'&gt;108&lt;/span&gt;
&lt;span class='line-number'&gt;109&lt;/span&gt;
&lt;span class='line-number'&gt;110&lt;/span&gt;
&lt;span class='line-number'&gt;111&lt;/span&gt;
&lt;span class='line-number'&gt;112&lt;/span&gt;
&lt;span class='line-number'&gt;113&lt;/span&gt;
&lt;span class='line-number'&gt;114&lt;/span&gt;
&lt;span class='line-number'&gt;115&lt;/span&gt;
&lt;span class='line-number'&gt;116&lt;/span&gt;
&lt;span class='line-number'&gt;117&lt;/span&gt;
&lt;span class='line-number'&gt;118&lt;/span&gt;
&lt;span class='line-number'&gt;119&lt;/span&gt;
&lt;span class='line-number'&gt;120&lt;/span&gt;
&lt;span class='line-number'&gt;121&lt;/span&gt;
&lt;span class='line-number'&gt;122&lt;/span&gt;
&lt;span class='line-number'&gt;123&lt;/span&gt;
&lt;span class='line-number'&gt;124&lt;/span&gt;
&lt;span class='line-number'&gt;125&lt;/span&gt;
&lt;span class='line-number'&gt;126&lt;/span&gt;
&lt;span class='line-number'&gt;127&lt;/span&gt;
&lt;span class='line-number'&gt;128&lt;/span&gt;
&lt;span class='line-number'&gt;129&lt;/span&gt;
&lt;span class='line-number'&gt;130&lt;/span&gt;
&lt;span class='line-number'&gt;131&lt;/span&gt;
&lt;span class='line-number'&gt;132&lt;/span&gt;
&lt;span class='line-number'&gt;133&lt;/span&gt;
&lt;span class='line-number'&gt;134&lt;/span&gt;
&lt;span class='line-number'&gt;135&lt;/span&gt;
&lt;span class='line-number'&gt;136&lt;/span&gt;
&lt;span class='line-number'&gt;137&lt;/span&gt;
&lt;span class='line-number'&gt;138&lt;/span&gt;
&lt;span class='line-number'&gt;139&lt;/span&gt;
&lt;span class='line-number'&gt;140&lt;/span&gt;
&lt;span class='line-number'&gt;141&lt;/span&gt;
&lt;span class='line-number'&gt;142&lt;/span&gt;
&lt;span class='line-number'&gt;143&lt;/span&gt;
&lt;span class='line-number'&gt;144&lt;/span&gt;
&lt;span class='line-number'&gt;145&lt;/span&gt;
&lt;span class='line-number'&gt;146&lt;/span&gt;
&lt;span class='line-number'&gt;147&lt;/span&gt;
&lt;span class='line-number'&gt;148&lt;/span&gt;
&lt;span class='line-number'&gt;149&lt;/span&gt;
&lt;span class='line-number'&gt;150&lt;/span&gt;
&lt;span class='line-number'&gt;151&lt;/span&gt;
&lt;span class='line-number'&gt;152&lt;/span&gt;
&lt;span class='line-number'&gt;153&lt;/span&gt;
&lt;span class='line-number'&gt;154&lt;/span&gt;
&lt;span class='line-number'&gt;155&lt;/span&gt;
&lt;span class='line-number'&gt;156&lt;/span&gt;
&lt;span class='line-number'&gt;157&lt;/span&gt;
&lt;span class='line-number'&gt;158&lt;/span&gt;
&lt;span class='line-number'&gt;159&lt;/span&gt;
&lt;span class='line-number'&gt;160&lt;/span&gt;
&lt;span class='line-number'&gt;161&lt;/span&gt;
&lt;span class='line-number'&gt;162&lt;/span&gt;
&lt;span class='line-number'&gt;163&lt;/span&gt;
&lt;span class='line-number'&gt;164&lt;/span&gt;
&lt;span class='line-number'&gt;165&lt;/span&gt;
&lt;span class='line-number'&gt;166&lt;/span&gt;
&lt;span class='line-number'&gt;167&lt;/span&gt;
&lt;span class='line-number'&gt;168&lt;/span&gt;
&lt;span class='line-number'&gt;169&lt;/span&gt;
&lt;span class='line-number'&gt;170&lt;/span&gt;
&lt;span class='line-number'&gt;171&lt;/span&gt;
&lt;span class='line-number'&gt;172&lt;/span&gt;
&lt;span class='line-number'&gt;173&lt;/span&gt;
&lt;span class='line-number'&gt;174&lt;/span&gt;
&lt;span class='line-number'&gt;175&lt;/span&gt;
&lt;span class='line-number'&gt;176&lt;/span&gt;
&lt;span class='line-number'&gt;177&lt;/span&gt;
&lt;span class='line-number'&gt;178&lt;/span&gt;
&lt;span class='line-number'&gt;179&lt;/span&gt;
&lt;span class='line-number'&gt;180&lt;/span&gt;
&lt;span class='line-number'&gt;181&lt;/span&gt;
&lt;span class='line-number'&gt;182&lt;/span&gt;
&lt;span class='line-number'&gt;183&lt;/span&gt;
&lt;span class='line-number'&gt;184&lt;/span&gt;
&lt;span class='line-number'&gt;185&lt;/span&gt;
&lt;span class='line-number'&gt;186&lt;/span&gt;
&lt;span class='line-number'&gt;187&lt;/span&gt;
&lt;span class='line-number'&gt;188&lt;/span&gt;
&lt;span class='line-number'&gt;189&lt;/span&gt;
&lt;span class='line-number'&gt;190&lt;/span&gt;
&lt;span class='line-number'&gt;191&lt;/span&gt;
&lt;span class='line-number'&gt;192&lt;/span&gt;
&lt;span class='line-number'&gt;193&lt;/span&gt;
&lt;span class='line-number'&gt;194&lt;/span&gt;
&lt;span class='line-number'&gt;195&lt;/span&gt;
&lt;span class='line-number'&gt;196&lt;/span&gt;
&lt;span class='line-number'&gt;197&lt;/span&gt;
&lt;span class='line-number'&gt;198&lt;/span&gt;
&lt;span class='line-number'&gt;199&lt;/span&gt;
&lt;span class='line-number'&gt;200&lt;/span&gt;
&lt;span class='line-number'&gt;201&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#!/opt/bin/bash&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# @todo: Don&amp;#39;t delete parent dir if Dir == Root&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# @todo: Root = $1 - But what about series!&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +x
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/opt/bin:/opt/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/syno/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/syno/bin:/usr/syno/sbin:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/syno/bin:/usr/syno/sbin:/usr/local/bin:/usr/local/sbin&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Locking&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;LockFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/volume1/downloads/nas_is_unpacking.lock&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;&amp;quot;${LockFile}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Lockfile still exists: ${LockFile}. Aborting&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;{ rm -f ${LockFile} ; exit 255; }&amp;quot;&lt;/span&gt; EXIT
&lt;/span&gt;&lt;span class='line'&gt;date &amp;gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LockFile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Running ${0} on $(date)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/volume1/downloads&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(pwd)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Purged&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Downloadstation&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Looking for downloadstation tasks...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Root&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/_queue -mmin +5 -iname &lt;span class="s1"&gt;&amp;#39;*.nzb&amp;#39;&lt;/span&gt; -o -iname &lt;span class="s1"&gt;&amp;#39;*.torrent&amp;#39;&lt;/span&gt; |sort | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;File; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$File&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Prevdir}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;= $(pwd)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;================================================================================================&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c"&gt;# Process the first par file in this directory thanks to |sort&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  /opt/bin/downloadstation add &lt;span class="s2"&gt;&amp;quot;${File}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; -eq 0 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Successfully added ${File}; purging file&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      rm -f &lt;span class="s2"&gt;&amp;quot;${File}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Unable to add ${File}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi  &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Home}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# PAR&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Looking for files to repair...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Root&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; -mmin +5 -iname &lt;span class="s1"&gt;&amp;#39;*.par2&amp;#39;&lt;/span&gt; |sort | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;File; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$File&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Prevdir}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;= $(pwd)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;================================================================================================&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# Process the first par file in this directory thanks to |sort&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      par2 r &lt;span class="s2"&gt;&amp;quot;${File}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; -eq 0 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;          &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Successfully repaired; purging par files&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          rm -f *.par2
&lt;/span&gt;&lt;span class='line'&gt;          rm -f *.PAR2
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;          &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Unable to repair; purging entire directory&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nv"&gt;Purged&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${Purged}${Dir}\n&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/span&gt;&lt;span class='line'&gt;          rm -rf &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Home}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# RAR&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Looking for rar files to unpack...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Root&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; -mmin +5 -iname &lt;span class="s1"&gt;&amp;#39;*.rar&amp;#39;&lt;/span&gt; |sort | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;File; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$File&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Prevdir}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;= $(pwd)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;================================================================================================&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# Process the first rar file in this directory thanks to |sort&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      unrar e -y -o+ -p- &lt;span class="s2"&gt;&amp;quot;${File}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; -eq 0 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;          &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Successfully unpacked; purging rar files&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          rm -f *.rar
&lt;/span&gt;&lt;span class='line'&gt;          rm -f *.r&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;][&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          rm -f *.s&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;][&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          rm -f *.t&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;][&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;          &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Unable to unpack; purging entire directory&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nv"&gt;Purged&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${Purged}${Dir}\n&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/span&gt;&lt;span class='line'&gt;          rm -rf &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Home}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# 7zip&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Looking for 7zip files to unpack...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Root&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; -mmin +5 -iname &lt;span class="s1"&gt;&amp;#39;*.7z.001&amp;#39;&lt;/span&gt; |sort | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;File; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$File&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Prevdir}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;= $(pwd)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;================================================================================================&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# Process the first 7zip file in this directory thanks to |sort&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      7z x &lt;span class="s2"&gt;&amp;quot;${File}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; -eq 0 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;          &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Successfully unpacked; purging rar files&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          rm -f *.7z.&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;][&lt;/span&gt;0-9&lt;span class="o"&gt;][&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;          &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Unable to unpack; purging entire directory&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nv"&gt;Purged&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${Purged}${Dir}\n&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/span&gt;&lt;span class='line'&gt;          rm -rf &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Home}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Move 1 Dir up &amp;amp; rename to parent dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Looking for files to clean...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Root&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; -mmin +5 -iname &lt;span class="s1"&gt;&amp;#39;*.mkv&amp;#39;&lt;/span&gt; -o -iname &lt;span class="s1"&gt;&amp;#39;*.avi&amp;#39;&lt;/span&gt; |sort | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;File; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$File&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Prevdir}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;= $(pwd)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;================================================================================================&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.1 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.2 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.nzb 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.nfo 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.par2_hellanzb_dupe0 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.sfv 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.srr 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *.segment000&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# in the middle&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *&lt;span class="o"&gt;[&lt;/span&gt;.-&lt;span class="o"&gt;][&lt;/span&gt;Ss&lt;span class="o"&gt;][&lt;/span&gt;Aa&lt;span class="o"&gt;][&lt;/span&gt;Mm&lt;span class="o"&gt;][&lt;/span&gt;Pp&lt;span class="o"&gt;][&lt;/span&gt;Ll&lt;span class="o"&gt;][&lt;/span&gt;Ee&lt;span class="o"&gt;][&lt;/span&gt;.-&lt;span class="o"&gt;]&lt;/span&gt;*.&lt;span class="o"&gt;{&lt;/span&gt;mkv,avi,mpg,srs&lt;span class="o"&gt;}&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# at the end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      rm -f *&lt;span class="o"&gt;[&lt;/span&gt;.-&lt;span class="o"&gt;][&lt;/span&gt;Ss&lt;span class="o"&gt;][&lt;/span&gt;Aa&lt;span class="o"&gt;][&lt;/span&gt;Mm&lt;span class="o"&gt;][&lt;/span&gt;Pp&lt;span class="o"&gt;][&lt;/span&gt;Ll&lt;span class="o"&gt;][&lt;/span&gt;Ee&lt;span class="o"&gt;]&lt;/span&gt;.&lt;span class="o"&gt;{&lt;/span&gt;mkv,avi,mpg,srs&lt;span class="o"&gt;}&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# at the beginning&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      rm -f &lt;span class="o"&gt;[&lt;/span&gt;Ss&lt;span class="o"&gt;][&lt;/span&gt;Aa&lt;span class="o"&gt;][&lt;/span&gt;Mm&lt;span class="o"&gt;][&lt;/span&gt;Pp&lt;span class="o"&gt;][&lt;/span&gt;Ll&lt;span class="o"&gt;][&lt;/span&gt;Ee&lt;span class="o"&gt;][&lt;/span&gt;.-&lt;span class="o"&gt;]&lt;/span&gt;*.&lt;span class="o"&gt;{&lt;/span&gt;mkv,avi,mpg,srs&lt;span class="o"&gt;}&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# complete&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      rm -f &lt;span class="o"&gt;[&lt;/span&gt;Ss&lt;span class="o"&gt;][&lt;/span&gt;Aa&lt;span class="o"&gt;][&lt;/span&gt;Mm&lt;span class="o"&gt;][&lt;/span&gt;Pp&lt;span class="o"&gt;][&lt;/span&gt;Ll&lt;span class="o"&gt;][&lt;/span&gt;Ee&lt;span class="o"&gt;]&lt;/span&gt;.&lt;span class="o"&gt;{&lt;/span&gt;mkv,avi,mpg,srs&lt;span class="o"&gt;}&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="c"&gt;# Synology media thumbs&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      rm -rf @eaDir
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Home}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Move lonely files 1 dir up &amp;amp; rename to parent dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Looking for lonely files to promote 1 directory up...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Root&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; -mmin +5 -iname &lt;span class="s1"&gt;&amp;#39;*.mkv&amp;#39;&lt;/span&gt; -o -iname &lt;span class="s1"&gt;&amp;#39;*.avi&amp;#39;&lt;/span&gt; -o -iname &lt;span class="s1"&gt;&amp;#39;*.ts&amp;#39;&lt;/span&gt; |sort | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;File; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$File&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;Parent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(dirname &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Prevdir}&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$(ls -l |grep -v &amp;#39;total &amp;#39; |wc -l)&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;          &lt;/span&gt;&lt;span class="nv"&gt;Basedir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(basename &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nv"&gt;Newname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(echo &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Basedir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nv"&gt;Ext&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;File&lt;/span&gt;&lt;span class="p"&gt;##*.&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nv"&gt;Newname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${Newname}.${Ext}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="c"&gt;#cmd=&amp;quot;mv \&amp;quot;${File}\&amp;quot; \&amp;quot;${Parent}/${Newname}\&amp;quot; &amp;amp;&amp;amp; rmdir \&amp;quot;${Dir}\&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          mv &lt;span class="s2"&gt;&amp;quot;${File}&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Parent}/${Newname}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rmdir &lt;span class="s2"&gt;&amp;quot;${Dir}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;promoted: ${Parent}/${Newname}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Prevdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Dir&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;${Home}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;## TV Episodes&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# Please use FileBot instead. Much better results.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#if [ &amp;quot;${1}&amp;quot; = &amp;quot;tvnamer&amp;quot; ]; then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# echo &amp;quot;Looking for tv episodes to rename...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# tvnamer -r --batch /volume1/video/series&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# REPORT&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;${Purged}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Had to purge these directories cause they were damaged beyond repair:&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;${Purged}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Done&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It runs every 15 minutes by cron, will remove broken downloads, unpack complete downloads, move lonely files 1 directory up,
delete a bunch of unwanted extensions, etc.
It makes a few assumptions (e.g. downloads must be in &lt;code&gt;/volume1/downloads&lt;/code&gt;), so be sure to only use it for inspiration.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a work in progress, and improvements are more than welcome.&lt;/p&gt;

&lt;h3&gt;Downloadstation CLI&lt;/h3&gt;

&lt;p&gt;To have your Synology scan a directory for new download tasks, you can use Downloadstation CLI.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ipkg install python24 py-pgsql py24-mx-base
&lt;/span&gt;&lt;span class='line'&gt;wget -O- http://downloadstation.jroene.de/downloadstation &amp;gt; /opt/bin/downloadstation
&lt;/span&gt;&lt;span class='line'&gt;chmod 755 /opt/bin/downloadstation
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;With the command&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;downloadstation add &amp;lt;nzbfile&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The download will be added to the queue. If you use an adaptation of my unpacker script,
it will already automatically scan &lt;code&gt;/volume1/downloads/_queue&lt;/code&gt; for any new torrent or
nzb task.&lt;/p&gt;

&lt;h3&gt;Tools&lt;/h3&gt;

&lt;p&gt;These programs may take up a little bit of space, but won&amp;#8217;t be active in
memory until you call upon them (except for &lt;code&gt;cron&lt;/code&gt;), so feel free to
install without performance loss:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ipkg install vim bash bash-completion less rsync mtr &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  sudo tshark htop openssl mlocate perl ack hdparm sysstat dstat &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  bzip2 unrar unzip zlib p7zip wget
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;wget -O- --no-check-certificate https://raw.github.com/timkay/solo/master/solo &amp;gt; /usr/bin/solo
&lt;/span&gt;&lt;span class='line'&gt;chmod a+x /usr/bin/solo
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Optionally do &lt;code&gt;ipkg install clamav&lt;/code&gt; so you can run &lt;code&gt;clamscan&lt;/code&gt; on freshly downloaded files
and check them for viruses (I decided not to).&lt;/p&gt;

&lt;h3&gt;Renaming files&lt;/h3&gt;

&lt;p&gt;There&amp;#8217;s a neat program called &lt;a href="https://github.com/dbr/tvnamer"&gt;tvnamer&lt;/a&gt; that will
rename all your TV series files.&lt;/p&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ipkg install python25 py25-setuptools git
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /volume1/@tmp
&lt;/span&gt;&lt;span class='line'&gt;git clone https://github.com/dbr/tvnamer.git
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;tvnamer
&lt;/span&gt;&lt;span class='line'&gt;python setup.py install
&lt;/span&gt;&lt;span class='line'&gt;ln -s /opt/local/bin/tvnamer /usr/bin/tvnamer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Use:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tvrenamer -r /volume1/video/tv
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://filebot.sourceforge.net/"&gt;FileBot&lt;/a&gt; is even better but requires a GUI.&lt;/p&gt;

&lt;h3&gt;Crontab&lt;/h3&gt;

&lt;p&gt;Crontab works slightly different than on more high-level Operating Systems.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s how to edit your crontab:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;vim /etc/crontab
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Every job needs a user prefix. e.g. &lt;code&gt;root&lt;/code&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;*/15 * * * * root /usr/bin/solo -port&lt;span class="o"&gt;=&lt;/span&gt;1111 /volume1/video/unpacker.sh 1&amp;gt;&amp;amp;2 &amp;gt; /volume1/@tmp/unpacker.log
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;When you&amp;#8217;re done editing the new crontab, reload it by executing:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;/usr/syno/etc.defaults/rc.d/S??crond.sh stop
&lt;/span&gt;&lt;span class='line'&gt;/usr/syno/etc.defaults/rc.d/S??crond.sh start
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;Tmux or Screen&lt;/h3&gt;

&lt;p&gt;If you start programs from within &lt;a href="http://tmux.sourceforge.net/"&gt;tmux&lt;/a&gt;, you can
close your SSH session without killing it. You can check back later on it
with &lt;code&gt;tmux attach || tmux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This makes it perfect to run cleanup/rename scripts in while you&amp;#8217;re still experimenting
and need to check up on them regularly.&lt;/p&gt;

&lt;p&gt;Tmux similar to &lt;a href="http://www.gnu.org/software/screen/manual/screen.html"&gt;screen&lt;/a&gt;,
but I think it&amp;#8217;s a bit easier to deal with (just &lt;code&gt;tmux attach || tmux&lt;/code&gt; is all).&lt;/p&gt;

&lt;p&gt;However &lt;code&gt;screen&lt;/code&gt; is a lot easier to install thanks to &lt;code&gt;ipkg&lt;/code&gt;, so pick your poison.&lt;/p&gt;

&lt;h4&gt;Screen&lt;/h4&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ipkg install screen
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h4&gt;Tmux&lt;/h4&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ipkg install libevent optware-devel ncurses-dev
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# http://forum.synology.com/enu/viewtopic.php?f=90&amp;amp;t=30132&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;mkdir /opt/arm-none-linux-gnueabi/lib_disabled
&lt;/span&gt;&lt;span class='line'&gt;mv /opt/arm-none-linux-gnueabi/lib/libpthread* /opt/arm-none-linux-gnueabi/lib_disabled
&lt;/span&gt;&lt;span class='line'&gt;cp /lib/libpthread.so.0 /opt/arm-none-linux-gnueabi/lib/
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/arm-none-linux-gnueabi/lib/
&lt;/span&gt;&lt;span class='line'&gt;ln -s libpthread.so.0 libpthread.so
&lt;/span&gt;&lt;span class='line'&gt;ln -s libpthread.so.0 libpthread-2.5.so
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /volume1/@tmp
&lt;/span&gt;&lt;span class='line'&gt;wget http://sunet.dl.sourceforge.net/project/tmux/tmux/tmux-1.4/tmux-1.4.tar.gz
&lt;/span&gt;&lt;span class='line'&gt;tar -zxvf tmux-1.4.tar.gz
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;tmux-1.4
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gcc
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-L /opt/lib -I  /opt/include/ncurses&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;./configure --prefix&lt;span class="o"&gt;=&lt;/span&gt;/opt &lt;span class="c"&gt;# prefix is not supported. So we&amp;#39;ll need some symlinks&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;make &lt;span class="c"&gt;# This will take a while&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;make install
&lt;/span&gt;&lt;span class='line'&gt;ln -s /opt/lib/libevent-1.4.so.2 /usr/lib/libevent-1.4.so.2
&lt;/span&gt;&lt;span class='line'&gt;ln -s /opt/share/terminfo/* /usr/share/terminfo/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;!-- Generated by Rakefile:build --&gt;


&lt;h3&gt;Imported comments&lt;/h3&gt;

&lt;p&gt;These were imported from my old blog. Please use disqus below for new comments&lt;/p&gt;

&lt;div style="padding: 3px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; overflow-y: scroll; max-height: 500px;"&gt;
&lt;p&gt;
&lt;strong&gt;
BC
&lt;/strong&gt;
on 2012-09-10 18:49:16 &lt;br /&gt;
Thanks for taking the time to write this up.   I just upgraded to DSM 4.1 and I had to revisit this issue.  This time I found a work-around.  I&amp;#8217;m just using the DS to archive photos (not view them) so I didn&amp;#8217;t care at all about thumbnail generation (or indexing).  By moving the photo files OUT of the &amp;
quot;/Photos&amp;
quot; directory, DSM will ignore indexing/thumbnail creation.  (By default it will index and create thumbnails for anything put into a folder called &amp;
quot;/Photos&amp;
quot;.    It seems to have done the trick (I just created a separate shared folder called &amp;
quot;/Archives&amp;
quot; and made sure that under the Media Indexing Service (in Control Panel) that this folder was NOT set to be indexed under the &amp;
quot;Indexed Folder&amp;
quot; tab.  (&amp;
quot;/Photos&amp;
quot; is a default that cannot be removed from Indexing).&lt;br /&gt;
&lt;br /&gt;
On a separate note, I would like to start using my Synology for downloading, but need to set it up with a VPN first (I want a secure tunnel).  I use Viscosity on my Macs as a VPN client but I&amp;#8217;m confused as to how to set up a VPN *client* on the Synology (not set it up as a VPN *server*).&lt;br /&gt;
&lt;br /&gt;
Any suggestions?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Daniel Orum
&lt;/strong&gt;
on 2012-08-21 09:57:56 &lt;br /&gt;
Hello all.&lt;br /&gt;
&lt;br /&gt;
First of all, thanks for a great blog. very useful.&lt;br /&gt;
&lt;br /&gt;
But im having a problem with sab and my synology nas 207+ which i hope you guys could help out with.&lt;br /&gt;
&lt;br /&gt;
Im experiencing that the sab program is stopping regularly on my nas. If i download with 200kbps it can stay running for half a day, if i turn the speed up to 800kbps it normally shuts down after 2-3 hours. Im running sab, Couch Potato, python and sickbeard on my nas. They are all from Superzebulon.&lt;br /&gt;
&lt;br /&gt;
I have followed your blog, and i have stopped the processed that i dont use. Byt it dosen&amp;#8217;t seem to make a difference. I also tried following this tutorial: (crontab job)&lt;br /&gt;
&lt;br /&gt;
http://thanatosblog.wordpress.com/&lt;br /&gt;
&lt;br /&gt;
And under &amp;
quot;trouble with sab&amp;
quot;, i tried following the part where i entered a line in Crontab.&lt;br /&gt;
&lt;br /&gt;
But my problem is that i cant access crontab. Even with the commands:&lt;br /&gt;
&lt;br /&gt;
crontab -e&lt;br /&gt;
or&lt;br /&gt;
vim crontab&lt;br /&gt;
 Putty tells me: crontab: file not found&lt;br /&gt;
&lt;br /&gt;
And i cant, for the life of me, figure out what to do next. So even with the tweaks on this great blog, im still experiencing that sab is shutting down. Could soneone please help me figure out how i avoid this? And how do i get access to the crontab as described in this blog?&lt;br /&gt;
&lt;br /&gt;
Sorry for partially referring to another blog, but i just dont know where else to ask.&lt;br /&gt;
&lt;br /&gt;
Daniel&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Mark Smith
&lt;/strong&gt;
on 2012-07-25 09:55:41 &lt;br /&gt;
Thanks to René&amp;#8217;s post on 30 April 2011. It seems even Matthias Radig (the creator of Download CLI) is unaware of it&amp;#8217;s ability to handle nzb files.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Mark Smith
&lt;/strong&gt;
on 2012-07-25 08:44:54 &lt;br /&gt;
Hello,&lt;br /&gt;
&lt;br /&gt;
I was very interested in the Download CLI section. Your article gives the impression it can handle nzb files which it can not.&lt;br /&gt;
&lt;br /&gt;
Email received from Matthias Radig:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&lt;br /&gt;
The script does not support NZB downloads and I do not plan to add this feature myself.&lt;br /&gt;
However, as the script is licensed under the GPL, someone else might in&lt;br /&gt;
the future.&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Have I missed something?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Hugo
&lt;/strong&gt;
on 2012-03-10 22:23:10 &lt;br /&gt;
Problem was in solo, not in the redirection of stdout/stderr: I had some piece of HTML as program instead of the perl code&amp;#8230; See also comment #13.&lt;br /&gt;
&lt;br /&gt;
Gr. Hugo&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Hugo
&lt;/strong&gt;
on 2012-03-10 17:04:40 &lt;br /&gt;
Great introduction to using your syno full speed. Thanks!&lt;br /&gt;
&lt;br /&gt;
The redirect in the crontab file is not working (on my Syno). I changed this:&lt;br /&gt;
1&amp;
gt;&amp;
amp;2 &amp;
gt; &lt;br /&gt;
into:&lt;br /&gt;
2&amp;
gt;&amp;
amp;1 &amp;
gt; &lt;br /&gt;
(meaning stderr is redirected to the same file as stdout)&lt;br /&gt;
&lt;br /&gt;
Regards,&lt;br /&gt;
Hugo&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="None" rel="nofollow"&gt;Valie&lt;/a&gt;
&lt;/strong&gt;
on 2012-02-28 05:19:09 &lt;br /&gt;
Marcello, Upload Image files using Synology Assistant. In this way, the PC on which Assistant runs, will do the computing for thumbnails generation&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
moydeliche
&lt;/strong&gt;
on 2012-02-26 21:53:07 &lt;br /&gt;
Hi Kevin,&lt;br /&gt;
&lt;br /&gt;
Same issue as frey when lauching the script. Synthax errors are fournd&amp;#8230;&lt;br /&gt;
&lt;br /&gt;
Any idea?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
marcello
&lt;/strong&gt;
on 2012-01-27 13:44:13 &lt;br /&gt;
Hello, thanks for your advice. I have a DS211j which creates miniatures for my 50000 pictures in a very very slow.&lt;br /&gt;
Do you know a way to create thumbnails on the PC and then upload them to the NAS?&lt;br /&gt;
Thanks for attention. By&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
ritonlajoie
&lt;/strong&gt;
on 2011-12-10 20:52:08 &lt;br /&gt;
Hi ! Thanks a lot for your script.&lt;br /&gt;
I&amp;#8217;m having an issue with folders having multiple episodes in them. For example, a folder containing all the rar/par files for a whole season.&lt;br /&gt;
&lt;br /&gt;
The script will actually process the first file, then remove all the remaining. Is there any way you could look into improving your script ?&lt;br /&gt;
&lt;br /&gt;
Thanks !&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="www.espocartoons.com" rel="nofollow"&gt;espocartoons&lt;/a&gt;
&lt;/strong&gt;
on 2011-12-10 11:38:30 &lt;br /&gt;
Im really having difficulty editing or inputting  anew line in Crontab.&lt;br /&gt;
&lt;br /&gt;
I&amp;#8217;ve gone into the files using vim /etc/crontab&lt;br /&gt;
&lt;br /&gt;
but i cant enter a new line? I have messed around and managed to put a line between the two which are already in there but when i try to :quit it wont let me?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://iosguide.web.id" rel="nofollow"&gt;Michael&lt;/a&gt;
&lt;/strong&gt;
on 2011-11-27 04:59:49 &lt;br /&gt;
the section &amp;
quot;turning off media indexers&amp;
quot; really speed things up, thanks for the tips.&lt;br /&gt;
&lt;br /&gt;
still waiting for Synology to fix HTTP downloads in Download Station, I can only get 30-150KB/s with HTTP while I can get 600-900KB/s with torrents.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
wariyo
&lt;/strong&gt;
on 2011-11-21 17:05:14 &lt;br /&gt;
Is it possible to install FileBot CLI also on Synology NAS with PPC processor?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="filebot.sf.net" rel="nofollow"&gt;rednoah&lt;/a&gt;
&lt;/strong&gt;
on 2011-11-09 16:14:15 &lt;br /&gt;
FileBot as an awesome CLI, working very well for a few months now.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://twitter.com/sebster" rel="nofollow"&gt;Sebastian&lt;/a&gt;
&lt;/strong&gt;
on 2011-11-02 10:46:35 &lt;br /&gt;
Just a small modification (I just had to make the adjustments again because of the DSM update): The URL for the curl command to download &amp;
quot;solo&amp;
quot; should be https://raw.github.com/timkay/solo/master/solo if you don&amp;#8217;t want to download a redirected info page. Took me a moment to figure out why that can&amp;#8217;t be executed. ;-)&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Vince
&lt;/strong&gt;
on 2011-10-19 10:50:41 &lt;br /&gt;
Hi Kevin,&lt;br /&gt;
&lt;br /&gt;
Great article, makes me want to buy a DS411. I already have fun_plugged a CH3MNAS to be an automatic RSS torrent scanner/downloader, but I now have the cash to take it a step further; I want my own PHP/MySQL server and do the download thingy at the same location.&lt;br /&gt;
&lt;br /&gt;
So my question is: when I go berserk on inserting neat little ipkg files in that NAS, will I compromise the server functionality? I mean, you literally state: &amp;
quot;Here&amp;#8217;s how I turned my budget NAS that&amp;#8217;s mediocre at 8 things into a more powerful one that&amp;#8217;s good at 3 things: downloading / file serving / backups.&amp;
quot;&lt;br /&gt;
&lt;br /&gt;
Best,&lt;br /&gt;
Vince&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Frank
&lt;/strong&gt;
on 2011-10-12 19:50:16 &lt;br /&gt;
re: &amp;
quot;After testdriving it for a while I was never able to get it to download above 3MB/s (2 average).&amp;
quot; and &amp;
quot;The j is just not powerful enough to do SABnzbd at these speeds&amp;
quot;&lt;br /&gt;
&lt;br /&gt;
After installing sabnzbd and before it is restarted I can only get 3 Mbps and shutting down other services did not help. Only after restarting sabnzbd can it max out my bandwidth at 6 Mbps. Note that the Synology box may also have to be restarted too. Mine is restarted daily because I schedule it to power down on workdays during peak electricity rate.&lt;br /&gt;
&lt;br /&gt;
I only found out about this several days after installation after re-starting sabnzbd in my attempt to start the queue.  Restarting sabnzbd did not not fixed the queuing problem and it turned out to be caused by a schedule to pause all activities at that period. It did however, speed up my downloads.&lt;br /&gt;
&lt;br /&gt;
Software used:&lt;br /&gt;
DSM 3.2-1922; Build Date: 2011/09/06.&lt;br /&gt;
SABnzbd 0.6.9 spk is from synoblog.superzebulon.org/2011/09/sabnzbd-0-6-9-1-spk/&lt;br /&gt;
&lt;br /&gt;
Hardware:DS-211j&lt;br /&gt;
&lt;br /&gt;
Settings:&lt;br /&gt;
Download threads: 12 SSL connections, from Astraweb.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Frey
&lt;/strong&gt;
on 2011-10-01 02:07:39 &lt;br /&gt;
I am getting the followring erro meassage when i try running the unpacker.sh script&amp;#8230; any idea what i am doing wrong? :)&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&lt;br /&gt;
: command not found:&lt;br /&gt;
: invalid optione 5: set: +&lt;br /&gt;
set: usage: set [--abefhkmnptuvxBCHP] [-o option] [arg ...]&lt;br /&gt;
: command not found:&lt;br /&gt;
unpacker.sh: line 41: syntax error near unexpected token `fi'&lt;br /&gt;
'npacker.sh: line 41: ` fi&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.twitter.com/sebster" rel="nofollow"&gt;Sebastian&lt;/a&gt;
&lt;/strong&gt;
on 2011-09-29 08:22:16 &lt;br /&gt;
Thank you very much for the script.&lt;br /&gt;
I had the problem that after downloads finished, the whole volume1/downloads folder was disappearing. After a bit of poking around, I found out that the problem was some of the downloads ended on &amp;
quot;.par2&amp;
quot;, so the find command tried to repair those. The command &amp;
quot;-type f&amp;
quot; limits the search to files, and everything works just fine. Thanks again!&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
rednoah
&lt;/strong&gt;
on 2011-09-10 04:33:14 &lt;br /&gt;
FileBot will support CLI in with the next release. There is a test version available right now, check forums on sourceforge for details.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Tim
&lt;/strong&gt;
on 2011-06-22 19:46:07 &lt;br /&gt;
I followed your guide, but cannot seem to get my full connection speed. I have 120Mbit, but the speed is always around 6MB/s, which is not even half of what I have. Is this really the max? This is rather disappointing for a NAS marketed as a download box.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
h0me5k1n
&lt;/strong&gt;
on 2011-05-15 12:59:25 &lt;br /&gt;
Excellent article&amp;#8230;  I&amp;#8217;m using SABnzbd at the moment but I&amp;#8217;m sorely tempted to switch usenet downloading to Synologys own Download Station after reading this.  I&amp;#8217;ve had problems updating SABnzbd to the newest versions on occasion. &lt;br /&gt;
&lt;br /&gt;
I created a script to download torrents from RSS feeds (made before I was using a DiskStation).  I modified it to use jroenes DownloadStation-CLI to load the torrents; it could easily be modified to download nzbs via rss.  Using the comments from Rene they could be dropped into a directory on the internal webserver of the DiskStation and loaded from there&amp;#8230;..&lt;br /&gt;
&lt;br /&gt;
Just need to see if there&amp;#8217;s a way to generate a custom RSS feed to select nzbs that I want now :D&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
René
&lt;/strong&gt;
on 2011-04-30 00:24:23 &lt;br /&gt;
@Kevin: I might have found kind of a workaround for loading NZB files.&lt;br /&gt;
&lt;br /&gt;
It appears that Downloadstation CLI is expecting an URL to load the NZB file from. That&amp;#8217;s why the link appears as &amp;#8216;broken&amp;#8217; or &amp;#8216;unknown&amp;#8217; because downloadstation cannot find the path to the NZB file.&lt;br /&gt;
&lt;br /&gt;
What I have done now, is move the NZB file to a directory on the internal webserver of the diskstation. I then use the URL to this file, eg. http://diskstation/nzb/filename.nzb, as a parameter for Downloadstation CLI. So the commandline becomes:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/opt/bin/downloadstation add http://diskstation/nzb/filename.nzb&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
I don&amp;#8217;t delete the NZB file after adding it to downloadstation, because it would then again turn into a broken link.&lt;br /&gt;
&lt;br /&gt;
Instead, I let the unpacker script remove the NZB file when the download is completed and unpacked in the cleanup portion of the script.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Marc
&lt;/strong&gt;
on 2011-04-20 13:59:25 &lt;br /&gt;
The script is a really great idea for the auto check / unrar. Do know how I could do to only check the real par2 files (not the .vol files) (so file.par2 is taken, but file.vol000+01.par2 is not taken?&lt;br /&gt;
It interesting because sometimes there are more than one file in a nzb so there is more than one par2 file that is needed (file.par2, test.par2 and Newtest.par2). There will be 3 rar and 3 different par2 set. So instead of removing the complete par2 it could be great to remove only the files that are being tested. For example when file.par2 is done, only files starting by file.vol*.par2 (and file.par2) are deleted Not the par2 for test.par2)&lt;br /&gt;
&lt;br /&gt;
Thank you&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Kevin
&lt;/strong&gt;
on 2011-04-17 16:48:44 &lt;br /&gt;
@ uninb: Did you add the root user? Did you restart cron after making changes?&lt;br /&gt;
&lt;br /&gt;
@ René: Yeah, turns out CLI has no support for nzb and never will get that either :/&lt;br /&gt;
Still looking for a good solution for that..&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
René
&lt;/strong&gt;
on 2011-04-07 19:36:46 &lt;br /&gt;
Hello,&lt;br /&gt;
&lt;br /&gt;
Thank you for the tutorial. I have only one issue where you may be able to help me with.&lt;br /&gt;
&lt;br /&gt;
When I use: downloadstation add &amp;
lt;nzbfile&amp;
gt;, the download appears in the download queue, but a few seconds later it is marked as &amp;#8216;Broken link&amp;#8217; and the download failes.&lt;br /&gt;
&lt;br /&gt;
When I add the same nzbfile to the queue through the Synology Download Station appp it does work as expected.&lt;br /&gt;
&lt;br /&gt;
Did you run into that problem? I use a DS211 by the way.&lt;br /&gt;
&lt;br /&gt;
kind regards&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
uninb
&lt;/strong&gt;
on 2011-03-12 20:20:47 &lt;br /&gt;
Hi,&lt;br /&gt;
thank you for your great tutorial, but i cannot get working the crontab part. &lt;br /&gt;
I am somewhat of newbie to synology and bad using command line, but is it possible that there is a mistake in the crontab edit and /video/ should be /downloads/?&lt;br /&gt;
anyways my crontab refuses to to do what im trying, I have to do it manually&amp;#8230;&lt;br /&gt;
any ideas?&lt;br /&gt;
best regards&lt;br/&gt;
&lt;/p&gt;
&lt;/div&gt;



&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/Q6jHBVUsRNw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2011/02/28/optimize-your-synology-for-downloading/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Install SABnzbd, Sickbeard, Couchpotato on your Synology DSM 3 NAS]]></title>
    <link href="http://feedproxy.google.com/~r/kvz/~3/VFbZVNnrqYI/" />
    <updated>2011-01-28T13:00:00+01:00</updated>
    <id>http://kvz.io/blog/2011/01/28/install-sabnzbd-on-your-synology</id>
    <content type="html">&lt;p&gt;The Synology ships with a Download Station but it&amp;#8217;s not remotely as
advanced as &lt;a href="http://sabnzbd.org/"&gt;SABnzbd&lt;/a&gt;. What I mostly miss is automatic
par &amp;amp; unpacking of it&amp;#8217;s downloads. Here&amp;#8217;s how to fix that.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h2&gt;Warning&lt;/h2&gt;

&lt;p&gt;This article assumes you&amp;#8217;re somewhat skilled in Linux. By applying these
suggestions you could seriously mess up your Disk Station.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m doing this on a DS411j running DSM 3.0. Your mileage may vary.&lt;/p&gt;

&lt;h2&gt;Maybe you don&amp;#8217;t want SABnzbd after all&lt;/h2&gt;

&lt;p&gt;In &lt;a href="http://kvz.io/blog/2011/02/28/optimize-your-synology-for-downloading/"&gt;a later article&lt;/a&gt; I demonstrate
how much higher downloads speeds can be achieved by synology&amp;#8217;s own &lt;code&gt;nzbget&lt;/code&gt;, and a way
that you can still have automatic par &amp;amp; unpacking of it&amp;#8217;s downloads. I&lt;/p&gt;

&lt;h2&gt;First of all&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Turn off the Download Station (Config screen)&lt;/li&gt;
&lt;li&gt;Turn on SSH acccess (Terminal)&lt;/li&gt;
&lt;li&gt;Login as root (same password as admin) via SSH and type: &lt;code&gt;sh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://forum.synology.com/wiki/index.php/Overview-on-modifying-the-Synology-Server,-bootstrap,-ipkg-etc#How-to-install-ipkg"&gt;install ipkg&lt;/a&gt;,
which is like your Synology&amp;#8217;s secret AppStore.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Install SABnzbd &amp;amp; the family&lt;/h2&gt;

&lt;p&gt;The following method installs &lt;a href="http://sabnzbd.org/"&gt;SABnzbd&lt;/a&gt; as root. There are some
pretty serious risks involved with that so you may want to
change it to someone with less permissions.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ipkg install bzip2 par2cmdline unrar unzip zlib git
&lt;/span&gt;&lt;span class='line'&gt;ipkg install py26-cheetah py26-openssl python26
&lt;/span&gt;&lt;span class='line'&gt;install sabnzbdplus
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/local
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -d sickbeard/.git &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; git clone git://github.com/midgetspy/Sick-Beard.git sickbeard
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;sickbeard
&lt;/span&gt;&lt;span class='line'&gt;git pull
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/local
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt; -d couchpotato/.git &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; git clone git://github.com/RuudBurger/CouchPotato.git couchpotato
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;couchpotato
&lt;/span&gt;&lt;span class='line'&gt;git pull
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;Config&lt;/h2&gt;

&lt;p&gt;Most can be done via the webinterfaces, except for the standard port of CouchPotato,
which conflicts with the Synology interface (&lt;code&gt;:5000&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Open the file &lt;code&gt;/opt/local/couchpotato/config.ini&lt;/code&gt;, look  for the &lt;code&gt;[global]&lt;/code&gt; header and change
the &lt;code&gt;port&lt;/code&gt; key to: &lt;code&gt;9300&lt;/code&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;global&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 9300
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;Startup&lt;/h2&gt;

&lt;p&gt;Create a startup file:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; EOT &amp;gt; /usr/syno/etc/rc.d/S99SABnzbd.sh&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;#!/usr/bin/env sh&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;if [ &amp;quot;start&amp;quot; = &amp;quot;\$1&amp;quot; ]; then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  /opt/bin/python2.6 /opt/share/SABnzbd/SABnzbd.py -f /root/.sabnzbd/sabnzbd.ini -s 0.0.0.0:9200 -d&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  /opt/bin/python2.6 /opt/local/couchpotato/CouchPotato.py --config=/opt/local/couchpotato/config.ini --datadir=/volume1 -d&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  /opt/bin/python2.6 /opt/local/sickbeard/SickBeard.py --quiet --port 9400 --config /opt/local/sickbeard/config.ini --datadir=/volume1 --daemon&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;elif [ &amp;quot;stop&amp;quot; = &amp;quot;\$1&amp;quot; ]; then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  /usr/bin/killall -9 python2.6&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;elif [ &amp;quot;restart&amp;quot; = &amp;quot;\$1&amp;quot; ]; then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  \$0 stop&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  \$0 start&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;elif [ &amp;quot;&amp;quot; = &amp;quot;\$1&amp;quot; ]; then&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;  echo &amp;quot;Start, stop or restart service? Use a parameter...&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;EOT&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Make it executable:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;chmod +x /usr/syno/etc/rc.d/S99SABnzbd.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;And run it:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;/usr/syno/etc/rc.d/S99SABnzbd.sh start
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Connect to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;http://[your_nas_ip]:9200/ for SABnzbd&lt;/li&gt;
&lt;li&gt;http://[your_nas_ip]:9300/ for CouchPotate&lt;/li&gt;
&lt;li&gt;http://[your_nas_ip]:9400/ for Sickbeard&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Next time your Synology boots, SABnzbd and it&amp;#8217;s family will boot as well.&lt;/p&gt;

&lt;!-- Generated by Rakefile:build --&gt;


&lt;h3&gt;Imported comments&lt;/h3&gt;

&lt;p&gt;These were imported from my old blog. Please use disqus below for new comments&lt;/p&gt;

&lt;div style="padding: 3px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; overflow-y: scroll; max-height: 500px;"&gt;
&lt;p&gt;
&lt;strong&gt;
Tom
&lt;/strong&gt;
on 2012-09-01 01:41:08 &lt;br /&gt;
Does the startup file work with the latest DSM release?  I have it set as executable but nothing happens?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Shane
&lt;/strong&gt;
on 2012-04-09 21:53:49 &lt;br /&gt;
This was very helpful to me.&lt;br /&gt;
&lt;br /&gt;
Thank you!!&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Andre
&lt;/strong&gt;
on 2012-02-13 10:56:51 &lt;br /&gt;
Hi,&lt;br /&gt;
&lt;br /&gt;
Thanks for the article its a great source of information but I wonder will this allow the synology to run sabnzbd automatically even though the computer is powered off.&lt;br /&gt;
&lt;br /&gt;
Im searching for some information which allows the synology to do this.&lt;br /&gt;
&lt;br /&gt;
Thanks again great article.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Doodlydood
&lt;/strong&gt;
on 2012-01-26 16:23:09 &lt;br /&gt;
Great article.  A note that one can add Zebulon&amp;#8217;s repository and install these applications through the package manager interface on the Synology as well.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Derek
&lt;/strong&gt;
on 2011-11-02 07:35:12 &lt;br /&gt;
To fix the error&lt;br /&gt;
/opt/libexec/git-core/git-pull: line 236: tr: not found&lt;br /&gt;
&lt;br /&gt;
install textutils&lt;br /&gt;
&lt;br /&gt;
ipkg install textutils&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Tom
&lt;/strong&gt;
on 2011-10-28 16:00:49 &lt;br /&gt;
for the tr errors, just update busybox.  ipkg install busybox&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
hughmc
&lt;/strong&gt;
on 2011-08-26 06:14:27 &lt;br /&gt;
had to add /opt/bin to the PATH in /etc/rc&lt;br /&gt;
&lt;br /&gt;
not the best solution but it&amp;#8217;s working now.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
hughmc
&lt;/strong&gt;
on 2011-08-26 03:50:03 &lt;br /&gt;
now i can&amp;#8217;t get par2 to work hah! any tips?&lt;br /&gt;
&lt;br /&gt;
&amp;
quot;No PAR2 program found, repairs not possible&amp;
quot;&lt;br /&gt;
&lt;br /&gt;
par2cmdline is installed and in the path.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Hughmc
&lt;/strong&gt;
on 2011-08-24 11:29:57 &lt;br /&gt;
@KeNMaSTeR&lt;br /&gt;
&lt;br /&gt;
You are missing the tr binary from coreutils.&lt;br /&gt;
&lt;br /&gt;
ipkg install coreutils&lt;br /&gt;
&lt;br /&gt;
Will fix it! Also i have noted that to get the config.ini files you will need to run sickbeard and couch potato at least once. they will generate a whole bunch of files.&lt;br /&gt;
&lt;br /&gt;
so just type:&lt;br /&gt;
&lt;br /&gt;
/opt/bin/python2.6 /opt/local/couchpotato/CouchPotato.py&lt;br /&gt;
&lt;br /&gt;
&amp;
amp;&lt;br /&gt;
&lt;br /&gt;
/opt/bin/python2.6 /opt/local/sickbeard/SickBeard.py&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Jayberz
&lt;/strong&gt;
on 2011-08-21 21:25:47 &lt;br /&gt;
How to i link both sab and sick to do the post processing? i have read i need to connect yo the synology.. please help!!! everything else works a treat.. just want it to move the files one downloaded..&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
KeNMaSTeR
&lt;/strong&gt;
on 2011-08-01 00:20:32 &lt;br /&gt;
Hi i got these problem when i try the command git pull ?&lt;br /&gt;
&lt;br /&gt;
KeNMaSTeR&amp;
gt; cd couchpotato/&lt;br /&gt;
KeNMaSTeR&amp;
gt; git pull&lt;br /&gt;
/opt/libexec/git-core/git-pull: line 235: tr: not found&lt;br /&gt;
Your configuration specifies to merge with the ref &amp;#8216;master&amp;#8217;&lt;br /&gt;
from the remote, but no such ref was fetched.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Any solution, i&amp;#8217;m very newby in linux :_/&lt;br /&gt;
And because of this error i cant see the config.ini in both sickbeard and CP.&lt;br /&gt;
&lt;br /&gt;
Thx for the help ;)&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
JR
&lt;/strong&gt;
on 2011-07-02 00:17:09 &lt;br /&gt;
Why not just use Merty sabnzbd package that contains some nice tools, and upgrade build in.&lt;br /&gt;
Available for all synology models.&lt;br /&gt;
works great, and unpacking works (might have to install extra deccompressing apps), but unrar and zip works in the box (as far i remember)&lt;br /&gt;
Speed have never been a concent for me, used this since my first synology nas (a 407e)&lt;br /&gt;
&lt;br /&gt;
http://www.mertymade.com/syno/&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
arta
&lt;/strong&gt;
on 2011-06-14 14:28:30 &lt;br /&gt;
this site is full of energy&lt;br /&gt;
&amp;
lt;a href=&amp;
quot;http://www.artadesign.ir&amp;
quot;&amp;
gt;http://www.artadesign.ir&amp;
lt;/a&amp;
gt;&lt;br /&gt;
&amp;
lt;/div&amp;
gt;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Senne
&lt;/strong&gt;
on 2011-05-27 15:34:31 &lt;br /&gt;
@Ryan &lt;br /&gt;
You can always choose to install sab manually, using the src.tar.gz from sourceforge. Something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;
gt; shut down sab &lt;br /&gt;
&amp;
gt; make a dir (I put it in /opt/share/sab/)&lt;br /&gt;
&amp;
gt; wget http://sourceforge.net/projects/sabnzbdplus/files/sabnzbdplus/sabnzbd-0.6.2/SABnzbd-0.6.2-src.tar.gz/download&lt;br /&gt;
&amp;
gt; tar -xvzf SABnzbd-0.6.2-src.tar.gz&lt;br /&gt;
&lt;br /&gt;
I had the 0.5.6 ipkg installed first, so I dunno if there are more things that need to be done to get it working without it. You need to change the path in the start up file, obviously.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Ryan
&lt;/strong&gt;
on 2011-05-26 06:16:39 &lt;br /&gt;
The sab package in ipkg looks pretty old.  Can we easily upgrade to 0.6.2?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://stirideiasi.ro" rel="nofollow"&gt;stiri iasi&lt;/a&gt;
&lt;/strong&gt;
on 2011-05-25 14:21:07 &lt;br /&gt;
Oh man, i would like to have this Linux skills like you :)&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
alex
&lt;/strong&gt;
on 2011-05-22 06:53:06 &lt;br /&gt;
Well shit, I wished I had known that these boxes weren&amp;#8217;t powerful enough to download at my full speed. Oh well, at least everything is automated now and I don&amp;#8217;t have to worry about setting a bandwidth cap. No way I&amp;#8217;m giving up using Sabnzbd+.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Senne
&lt;/strong&gt;
on 2011-05-20 13:36:52 &lt;br /&gt;
I decided to use a more friendly way to shutdown each program and prevent accidental killing other python scripts that are running&lt;br /&gt;
&lt;br /&gt;
With login/pw:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
if [ &amp;
quot;start&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  /opt/bin/python2.6 /opt/share/SABnzbd/SABnzbd.py -f /root/.sabnzbd/sabnzbd.ini -s 0.0.0.0:9200 -d&lt;br /&gt;
  /opt/bin/python2.6 /opt/local/couchpotato/CouchPotato.py --config=/opt/local/couchpotato/config.ini --datadir=/volume1 -d&lt;br /&gt;
  /opt/bin/python2.6 /opt/local/sickbeard/SickBeard.py --quiet --port 9400 --config /opt/local/sickbeard/config.ini --datadir=/volume1 --daemon&lt;br /&gt;
elif [ &amp;
quot;stop&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  #shutdown sab&lt;br /&gt;
  /opt/bin/wget -q --delete-after &amp;
quot;http://localhost:9200/sabnzbd/api?mode=shutdown&amp;
amp;ma_username=SABUSER&amp;
amp;ma_password=SABPASSW&amp;
amp;apikey=YOURAPIKEY&amp;
quot; &lt;br /&gt;
  sleep 6s&lt;br /&gt;
&lt;br /&gt;
  #shutdown sick beard&lt;br /&gt;
  /opt/bin/wget -q --http-user=YOURSBLOGIN --http-password=YOURSBPASSW &amp;
quot;http://localhost:9400/home/shutdown/&amp;
quot; &lt;br /&gt;
  sleep 6s&lt;br /&gt;
&lt;br /&gt;
  #shutdown coachpotato &lt;br /&gt;
  /opt/bin/wget -q --http-user=YOURCPLOGIN --http-password=YOURCPPASSW &amp;
quot;http://localhost:9300/config/exit/&amp;
quot;&lt;br /&gt;
  sleep 6s&lt;br /&gt;
  &lt;br /&gt;
elif [ &amp;
quot;restart&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  \$0 stop&lt;br /&gt;
  \$0 start&lt;br /&gt;
elif [ &amp;
quot;&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  echo &amp;
quot;Start, stop or restart service? Use a parameter...&amp;
quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
without login/pw:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
if [ &amp;
quot;start&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  /opt/bin/python2.6 /opt/share/SABnzbd/SABnzbd.py -f /root/.sabnzbd/sabnzbd.ini -s 0.0.0.0:9200 -d&lt;br /&gt;
  /opt/bin/python2.6 /opt/local/couchpotato/CouchPotato.py --config=/opt/local/couchpotato/config.ini --datadir=/volume1 -d&lt;br /&gt;
  /opt/bin/python2.6 /opt/local/sickbeard/SickBeard.py --quiet --port 9400 --config /opt/local/sickbeard/config.ini --datadir=/volume1 --daemon&lt;br /&gt;
elif [ &amp;
quot;stop&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  #shutdown sab&lt;br /&gt;
  /opt/bin/wget -q --delete-after &amp;
quot;http://localhost:9200/sabnzbd/api?mode=shutdown&amp;
amp;apikey=YOURAPIKEY&amp;
quot; &lt;br /&gt;
  sleep 6s&lt;br /&gt;
&lt;br /&gt;
  #shutdown sick beard&lt;br /&gt;
  /opt/bin/wget -q &amp;
quot;http://localhost:9400/home/shutdown/&amp;
quot; &lt;br /&gt;
  sleep 6s&lt;br /&gt;
&lt;br /&gt;
  #shutdown coachpotato &lt;br /&gt;
  /opt/bin/wget -q &amp;
quot;http://localhost:9300/config/exit/&amp;
quot;&lt;br /&gt;
  sleep 6s&lt;br /&gt;
  &lt;br /&gt;
elif [ &amp;
quot;restart&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  \$0 stop&lt;br /&gt;
  \$0 start&lt;br /&gt;
elif [ &amp;
quot;&amp;
quot; = &amp;
quot;\$1&amp;
quot; ]; then&lt;br /&gt;
  echo &amp;
quot;Start, stop or restart service? Use a parameter...&amp;
quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Gaz
&lt;/strong&gt;
on 2011-05-13 23:14:48 &lt;br /&gt;
Hi. Cool guide, but I&amp;#8217;m stuck. Am trying to install on a DS1511+ but I cannot locate a py26-yenc package anywhere&amp;#8230; seems py25-yenc is the latest. Does anyone know where I can get the py26-yenc? Or should I just go with python25 for everything (removing python26) ?&lt;br /&gt;
Thanks&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Holly
&lt;/strong&gt;
on 2011-04-23 19:38:49 &lt;br /&gt;
Thanks Kevin and Simpic. Edited the script with VI and works now.&lt;br /&gt;
&lt;br /&gt;
Loopt als een tiet&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Jacob Korf
&lt;/strong&gt;
on 2011-04-20 19:55:56 &lt;br /&gt;
It worked!! I found out that I forgot to add the $1 to the elif [ &amp;
quot;&amp;
quot; = &amp;
quot;$1&amp;
quot;.&lt;br /&gt;
Now it&amp;#8217;s working properly!&lt;br /&gt;
Thanks a lot!&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Kevin
&lt;/strong&gt;
on 2011-04-19 15:57:55 &lt;br /&gt;
@ Jacob Korf: ls -al will do the trick (to view them) checkout the chmod manpage for differences between 700 and e.g. a+x. But I still think you haven&amp;#8217;t copied your startup script correctly cause it clearly says it tries to execute something on line 12 that it has no rights to. Like it would try to execute the ini file or something.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Jacob Korf
&lt;/strong&gt;
on 2011-04-19 14:24:57 &lt;br /&gt;
@Senne: I had this incident before too:), my problem was that my shared folder was called /korf/ on the synology, and the shared folder in Putty (SSH client) was /usbshare1/&lt;br /&gt;
&lt;br /&gt;
@Senne &amp;
amp; Kevin:&lt;br /&gt;
How is it possible to see the CHMOD rights?&lt;br /&gt;
&lt;br /&gt;
when I execute as following the rights should be allright?:&lt;br /&gt;
chmod +x /usr/syno/etc/rc.d/S99SABnzbd.sh&lt;br /&gt;
&lt;br /&gt;
Or is it better to use chmod 700 /usr/syno/etc/rc.d/S99SABnzbd.sh&lt;br /&gt;
&lt;br /&gt;
Thanks in advance&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Senne
&lt;/strong&gt;
on 2011-04-18 19:25:16 &lt;br /&gt;
The wrong free space was caused by a typo in my settings :) &amp;#8216;/Volume1/Usenet/&amp;#8217;  but it should be &amp;#8216;/volume1/Usenet/&amp;#8217;&lt;br /&gt;
&lt;br /&gt;
@Jacob Geen idee waar het aan kan liggen, ben zelf ook een ramp met linux :) Staan je (lees/schrijf) chmod rechten goed?&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Jacob Korf
&lt;/strong&gt;
on 2011-04-18 17:33:25 &lt;br /&gt;
Thanks Senne &amp;
amp; Kevin!&lt;br /&gt;
&lt;br /&gt;
I created the /root/.sabnzbd directory, and was able to create the .ini by executing the &amp;
quot;/opt/bin/python2.5 /opt/share/SABnzbd/SABnzbd.py -f /root/.sabnzbd/sabnzbd.ini  -s 0.0.0.0:9200 -d&amp;
quot; script manually.&lt;br /&gt;
But&amp;#8230; now when i execute the S99SABnzbd.sh start, i get the following message:&lt;br /&gt;
/usr/syno/etc/rc.d/S99SABnzbd.sh: line 12: /root/.sabnzbd/sabnzbd.ini: Permission denied&lt;br /&gt;
&lt;br /&gt;
Seems that I don&amp;#8217;t have the proper permission?&lt;br /&gt;
&lt;br /&gt;
Alvast bedankt, (thanks in advance)&lt;br /&gt;
&lt;br /&gt;
Jacob Korf&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Senne
&lt;/strong&gt;
on 2011-04-18 14:53:32 &lt;br /&gt;
For some reason the parameter placeholders get stripped when the script is saved. I used the vi editor to add them again as simpic stated. &lt;br /&gt;
&lt;br /&gt;
open the file using&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&lt;br /&gt;
vi /usr/syno/etc/rc.d/S99SABnzbd.sh&lt;br /&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
press &amp;#8216;a&amp;#8217; to go into edit mode and add the $1 on the correct places in the script. Exit the edit mode by pressing esc and type &amp;#8216;ZZ&amp;#8217; to safe and close.&lt;br /&gt;
&lt;br /&gt;
Now it should work just fine.&lt;br /&gt;
&lt;br /&gt;
Now my problem: I installed under root, so sabnzbd states that the disk space is &amp;
quot;1.85 GB Free Space&amp;
quot; which is obviously wrong since I have 175 GB of free space on my NAS. Is there I way to fix this? Otherwise the diskspace email is not send when needed.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Kevin
&lt;/strong&gt;
on 2011-04-18 14:11:55 &lt;br /&gt;
@ Jacob Korf: May try creating the parent directory of that ini configuration file first:&lt;br /&gt;
&lt;br /&gt;
mkdir -p /root/.sabnzbd&lt;br /&gt;
&lt;br /&gt;
Not sure why it says line 12. My example has the reference on line 3 so it might still be you have an error in your file.&lt;br /&gt;
&lt;br /&gt;
Als not sure why you&amp;#8217;re using either Vim or nano, when you can just copy-paste the heredoc.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Jacob Korf
&lt;/strong&gt;
on 2011-04-18 14:03:00 &lt;br /&gt;
You were right! I just changed the parameters using NANO (same as VI), because the $1 wasn&amp;#8217;t filled yet. But now i get the following error (but it does execute):&lt;br /&gt;
/usr/syno/etc/rc.d/S99SABnzbd.sh: line 12: /root/.sabnzbd/sabnzbd.ini: not found&lt;br /&gt;
&lt;br /&gt;
Thanks a lot! but still i can&amp;#8217;t start the SABnzbd server&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Kevin
&lt;/strong&gt;
on 2011-04-17 16:42:55 &lt;br /&gt;
@ Holly &amp;
amp; Jacob Korf: I agree with simpic, please make sure you pasted the file 100% correctly&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
TorRK
&lt;/strong&gt;
on 2011-04-16 12:16:13 &lt;br /&gt;
*EDIT&lt;br /&gt;
&lt;br /&gt;
Was able to run it with Holly&amp;#8217;s line &amp;
quot;opt/bin/python2.5 /opt/share/SABnzbd/SABnzbd.py -f /root/.sabnzbd/sabnzbd.ini  -s 0.0.0.0:9200 -d&amp;
quot; and get SABnzbd running. Had to run the start command again after completing setup&amp;#8230;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
TorRK
&lt;/strong&gt;
on 2011-04-16 11:29:48 &lt;br /&gt;
Hi there.&lt;br /&gt;
&lt;br /&gt;
NOOB alert&lt;br /&gt;
I get a &amp;
quot;-ash: usr/syno/etc/rc.d/S99SABnzbd.sh: not found&amp;
quot; error when running the last command&amp;#8230; something went wrong, but have no clue where. My guess is that the startup script wasn&amp;#8217;t created&amp;#8230;&lt;br /&gt;
&lt;br /&gt;
Please help.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
simpic
&lt;/strong&gt;
on 2011-04-15 21:24:41 &lt;br /&gt;
Jacob &amp;
amp; Holly&amp;#8230;&lt;br /&gt;
&lt;br /&gt;
Double check the script to make sure it has the $1 or $0 in the parameter placeholders.&lt;br /&gt;
&lt;br /&gt;
You might need to vi the script to add these if you just copied and pasted the lines in from the web page.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Jacob Korf
&lt;/strong&gt;
on 2011-04-15 13:29:36 &lt;br /&gt;
I have the same problem as Holly. Exactly the same. Are we doing something wrong? I already searched on several websites for this, but didn&amp;#8217;t find anything that I can use.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Holly
&lt;/strong&gt;
on 2011-03-26 23:25:15 &lt;br /&gt;
Hi,&lt;br /&gt;
&lt;br /&gt;
The auto start script does not seem to execute here.&lt;br /&gt;
&lt;br /&gt;
When i run &lt;pre&gt;&lt;code&gt; /usr/syno/etc/rc.d/S99SABnzbd.sh start&lt;/code&gt;&lt;/pre&gt; i get &lt;pre&gt;&lt;code&gt;Start, stop or restart service? Use a parameter...&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
running it with &lt;pre&gt;&lt;code&gt;/opt/bin/python2.5 /opt/share/SABnzbd/SABnzbd.py -f /root/.sabnzbd/sabnzbd.ini  -s 0.0.0.0:9200 -d&lt;/code&gt;&lt;/pre&gt; to start the script manually works OK.&lt;br /&gt;
&lt;br /&gt;
I&amp;#8217;m a linux noob, so perhaps you guys have some ideas.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
Kevin
&lt;/strong&gt;
on 2011-03-10 14:29:39 &lt;br /&gt;
@ Ovidio &amp;
amp; ege: Yeah SABnzb is really neat. However I found that my NAS wasn&amp;#8217;t really powerful enough for it. May wanna checkout this new article on higher Synology download speeds: http://kevin.vanzonneveld.net/techblog/article/optimize_your_synology_for_downloading/&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
ege
&lt;/strong&gt;
on 2011-02-21 22:45:31 &lt;br /&gt;
worked great! thank you very much for the clear instructions^^ hoping to discovering more useful programs that would run on these incredible pieces of hardware&amp;#8230;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;
&lt;a href="http://www.thinkovi.com" rel="nofollow"&gt;Ovidiu&lt;/a&gt;
&lt;/strong&gt;
on 2011-02-01 10:33:37 &lt;br /&gt;
Great setup you have there :) &lt;br /&gt;
&lt;br /&gt;
Thanks for sharing, i am also using SABnzbd on my linux machine, works great!&lt;br/&gt;
&lt;/p&gt;
&lt;/div&gt;



&lt;img src="http://feeds.feedburner.com/~r/kvz/~4/VFbZVNnrqYI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://kvz.io/blog/2011/01/28/install-sabnzbd-on-your-synology/</feedburner:origLink></entry>
  
</feed>
