<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>tmpfs /home/stan</title>
    <link>https://blog.angeloff.name/</link>
    <description>Stan Angeloff's blog, a collection of thoughts, rants &amp; research</description>
    <language>en</language>
    <lastBuildDate>Thu, 05 Mar 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://blog.angeloff.name/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>A year of building my own AI workspace</title>
      <link>https://blog.angeloff.name/post/2026/03/05/a-year-of-building-my-own-ai-workspace/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2026/03/05/a-year-of-building-my-own-ai-workspace/</guid>
      <pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[<p>A year ago I started building my own AI workspace. Not a wrapper. The actual low-level thing — streaming APIs, tool execution, prompt pipelines. It runs inside Neovim and talks to Anthropic, OpenAI and Google directly.</p>
<p>I built it because I needed it for work — as simple as that. PRDs, statements of work, R&amp;D spikes, client documentation, training materials from video transcriptions. Every feature exists because a real problem demanded it.</p>
<p>Here&#39;s what I learned.</p>
<ol>
<li><p><strong>Own your workspace.</strong> Models come and go. The workspace you build around them is yours. The difference between a generic chat UI and a workspace you control is the same difference between Notepad and Vim. Most people don&#39;t need that level of control. But if you&#39;re trying to push what&#39;s possible with AI, it changes everything. Something doesn&#39;t work the way you want? You fix it. You don&#39;t file a feature request.</p>
</li>
<li><p><strong>Tool calling is half the moat.</strong> Once your AI can use tools, you&#39;d think you need dozens. You don&#39;t. Bash, read, edit and write. Four tools. <a href="https://marioslab.io/">Mario Zechner</a> proved this with Pi — a minimal coding agent that&#39;s competitive with far heavier tools using nothing but those four. MCP is a nice incremental improvement but tool calling itself is the giant leap. The moment your model can read a file, run a command and write the result back — that&#39;s when it stops being a chatbot and starts being useful.</p>
</li>
<li><p><strong>Prompt engineering is the other half.</strong> Tool calling only gets you so far. Your workspace is only as good as the agents you build and the prompts you write. I use <a href="https://simonwillison.net/">Simon Willison&#39;s definition</a> of &quot;agent&quot; here — an LLM that iteratively reasons, calls tools, processes results and repeats until the task is done. The quality of that loop depends entirely on how well you set it up.</p>
</li>
<li><p><strong>There is NO magic.</strong> When I started, tools like Claude Code felt almost magical. After a year of building the same kind of system from the ground up they feel less like magic and more like carefully crafted software doing a lot of clever things under the hood. Clever != Magic. Understanding what&#39;s actually going on has made me a better engineer, not just a better user of these tools.</p>
</li>
</ol>
<p>My advice: go one level lower than you think you need to. Not another abstraction on top of an abstraction. Not another AI SDK wrapper. Build the actual thing. Write your own agents. Wire up your own tool execution. Parse your own streaming responses. The best way to understand AI tooling is to build it yourself. That&#39;s where the real learning happens.</p>
<p>I open-sourced everything I built — <a href="https://github.com/Flemma-Dev/flemma.nvim">Flemma</a>.</p>
]]></description>
    </item>
    <item>
      <title>Santa&apos;s Magic Mailbox</title>
      <link>https://blog.angeloff.name/post/2025/12/23/santas-magic-mailbox/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2025/12/23/santas-magic-mailbox/</guid>
      <pubDate>Tue, 23 Dec 2025 00:00:00 GMT</pubDate>
      <description><![CDATA[<p>Did you forget to mail those pesky Santa letters? No worries, got you covered — <a href="https://santasmagicmailbox.vercel.app">santasmagicmailbox.vercel.app</a>.</p>
]]></description>
    </item>
    <item>
      <title>Unix stdbuf and unbuffer</title>
      <link>https://blog.angeloff.name/post/2022/11/11/unix-stdbuf-and-unbuffer/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2022/11/11/unix-stdbuf-and-unbuffer/</guid>
      <pubDate>Fri, 11 Nov 2022 00:00:00 GMT</pubDate>
      <description><![CDATA[<p>One of the very few things that continues to amaze me is how a few seemingly simple constructs in Unix — standard output, pipes, etc. — hold their own despite all the tech churn we battle with every day. TIL: <a href="https://hmarr.com/blog/how-stdbuf-works/">stdbuf and unbuffer</a>.</p>
]]></description>
    </item>
    <item>
      <title>Shopify Q3 2022 Earnings</title>
      <link>https://blog.angeloff.name/post/2022/11/09/shopify-q3-2022-earnings/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2022/11/09/shopify-q3-2022-earnings/</guid>
      <pubDate>Wed, 09 Nov 2022 00:00:00 GMT</pubDate>
      <description><![CDATA[<p><a href="https://www.popularfintech.com/p/shopify-q3-2022-earnings-review-hiding">Shopify Q3 2022 Earnings Review</a> — &quot;Revenue growth has probably restored investor enthusiasm about the company. However, objectively, revenue growth might have overshadowed the problems of the declining gross profit margin and (still) escalating operating expenses.&quot;</p>
]]></description>
    </item>
    <item>
      <title>Welcome to Hell</title>
      <link>https://blog.angeloff.name/post/2022/11/05/welcome-to-hell/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2022/11/05/welcome-to-hell/</guid>
      <pubDate>Sat, 05 Nov 2022 00:00:00 GMT</pubDate>
      <description><![CDATA[<p>&quot;Anyhow, welcome to hell. This was your idea.&quot; — <a href="https://www.theverge.com/2022/10/28/23428132/elon-musk-twitter-acquisition-problems-speech-moderation">The Verge on Elon Musk buying Twitter</a>. &quot;The essential truth of every social network is that the product is content moderation.&quot;</p>
]]></description>
    </item>
    <item>
      <title>Evolving AI Art</title>
      <link>https://blog.angeloff.name/post/2022/11/03/evolving-ai-art/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2022/11/03/evolving-ai-art/</guid>
      <pubDate>Thu, 03 Nov 2022 00:00:00 GMT</pubDate>
      <description><![CDATA[<p><a href="https://www.youtube.com/watch?v=K8TG0ZwYu7Y">Evolving AI Art</a> — &quot;What is the point? Exploration.&quot; A truly remarkable video.</p>
<p><img src="/assets/images/mastodon/evolving-ai-art.jpg" alt="Imaginary creature with tentacles generated by AI"></p>
]]></description>
    </item>
    <item>
      <title>Remix acquired by Shopify</title>
      <link>https://blog.angeloff.name/post/2022/11/01/remix-acquired-by-shopify/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2022/11/01/remix-acquired-by-shopify/</guid>
      <pubDate>Tue, 01 Nov 2022 00:00:00 GMT</pubDate>
      <description><![CDATA[<p>Remix web framework <a href="https://remix.run/blog/remixing-shopify">acquired by Shopify</a>. Is this about Shopify continuing to offer a better developer experience (DX) or just an acqui-hire? Also on the cards, <a href="https://hydrogen.shopify.dev/roadmap/#remixing-hydrogen">Remixing Hydrogen</a>.</p>
]]></description>
    </item>
    <item>
      <title>Cross-compiling BusyBox to run on the Intel Atom Z3745 inside an ASUS MeMO Pad (ME176C)</title>
      <link>https://blog.angeloff.name/post/2015/01/03/cross-compiling-busybox/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2015/01/03/cross-compiling-busybox/</guid>
      <pubDate>Sat, 03 Jan 2015 13:30:00 GMT</pubDate>
      <description><![CDATA[<p>I recently acquired the very inexpensive <a href="http://www.asus.com/Tablets/ASUS_MeMO_Pad_7_ME176C/">ASUS MeMO Pad (ME176C)</a>. It&#39;s a <a href="https://www.youtube.com/watch?v=kPyVptxhJ9U">surprisingly great device</a> with an excellent screen and, best of all, a powerful <a href="http://ark.intel.com/products/80270/Intel-Atom-Processor-Z3745-2M-Cache-up-to-1_86-GHz">Intel Atom Z3745</a> inside. The tablet comes with Android 4.4 (KitKat), however I want to run Ubuntu LTS from a <code>chroot</code>. I soon discovered I needed to compile BusyBox from source in order to achieve this.</p>
<p>You should root your tablet following the <a href="http://forum.xda-developers.com/showpost.php?p=55229933&postcount=22">instructions on XDA Forums</a>. I strongly advise you grab the latest <a href="http://23pin.logdown.com/posts/230216-root-rootzenfone-14r">RootZenPhone from the official page</a>. I initially bricked the tablet using 1.4.6r, but had success with 1.4.6.8r. Make sure to back up all of your important information as you may have to factory reset in case the rooting fails.</p>
<h3>Prerequisites</h3>
<p>You will need Ubuntu 14.04 LTS (Trusty). If you are running a different operating system the steps may still work, however you will need to tweak package names.</p>
<h3>Android NDK</h3>
<p>In order to cross-compile BusyBox, we&#39;ll need the <a href="https://developer.android.com/tools/sdk/ndk/index.html#download">Android NDK</a>. Grab whatever is the latest revision (<tt>10d</tt> at the time of writing) and make sure to pick the correct architecture for your computer. If you are downloading from a terminal, please familiarise yourself with the Terms &amp; Conditions on the NDK page.</p>
<pre><code class="language-bash">cd /tmp
wget http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin
chmod a+x android-ndk-*.bin
./android-ndk-*.bin
</code></pre>
<h3>BusyBox from source</h3>
<p>Let&#39;s get started by cloning the BusyBox repisitory:</p>
<pre><code class="language-bash"># If you don&#39;t have Git installed:
#
#     sudo apt-get install -y git-core

cd /tmp
git clone git://git.busybox.net/busybox.git
</code></pre>
<p>We&#39;ll need to check out a stable release. At the time of writing, I had success compiling 1.23.0:</p>
<pre><code class="language-bash">cd /tmp/busybox
git checkout 1_23_0
</code></pre>
<p>With the Android NDK in place, we need to edit the default configuration file to set the correct paths and flags:</p>
<pre><code class="language-bash">cd /tmp/busybox

# Export a shell variable for easy access to the Android NDK path:
export ANDROID_NDK_ROOT=$( echo -n /tmp/android-ndk-*/ )

# Configure the cross-compiler prefix used by BusyBox:
sed &#39;s!^\(CONFIG_CROSS_COMPILER_PREFIX=\).*!\1&quot;&#39;$ANDROID_NDK_ROOT&#39;toolchains/x86-4.8/prebuilt/linux-x86_64/bin/i686-linux-android-&quot;!&#39; -i configs/android_ndk_defconfig

# Configure the cross-compiler root:
sed &#39;s!^\(CONFIG_SYSROOT=\).*!\1&quot;&#39;$ANDROID_NDK_ROOT&#39;platforms/android-19/arch-x86&quot;!&#39; -i configs/android_ndk_defconfig

# Configure CFLAGS for the Intel Atom:
sed &#39;s!^\(CONFIG_EXTRA_CFLAGS=\).*!\1&quot;-DANDROID -D__ANDROID__ -DSK_RELEASE -march=atom -m32 -ffast-math -mfpmath=sse -ftree-loop-if-convert -fschedule-insns -fsched-pressure -O2&quot;!&#39; -i configs/android_ndk_defconfig
</code></pre>
<p>The file we modified needs to be copied so BusyBox can read it:</p>
<pre><code class="language-bash">make android_ndk_defconfig
</code></pre>
<p>There are several issues when cross-compiling BusyBox. We need to turn options associated with them off to avoid compilation errors:</p>
<pre><code class="language-bash"># If you don&#39;t have ncurses headers installed:
#
#     sudo apt-get install -y libncurses5-dev

make menuconfig
</code></pre>
<p>With the graphical menu on-screen, make sure the following options are configured as instructed:</p>
<ul>
<li><font color="darkred">disable</font> <code>Coreutils ---&gt; touch -&gt; Add support for -h</code></li>
<li><font color="green">enable</font> <code>Login/Password Management Utilities ---&gt; Use internal crypt functions</code></li>
<li><font color="darkred">disable</font> <code>Linux System Utilities ---&gt; mdev</code></li>
<li><font color="green">enable</font> <code>Linux System Utilities ---&gt; mount</code></li>
<li><font color="green">enable</font> <code>Linux System Utilities ---&gt; umount</code></li>
<li><font color="darkred">disable</font> <code>Networking Utilities ---&gt; udhcp client (udhcpc)</code></li>
</ul>
<p>The default state of those options should be the inverse of what we need them configured at. As you turn an option on, additional ones may present themselves -- make sure to leave those untouched.</p>
<p>Tip: <code>&lt;Esc&gt;&lt;Esc&gt;</code> gets you to the previous screen. <code>&lt;Tab&gt;</code> let&#39;s you highlight the Exit button.</p>
<p>Exit and save the configuration with the new options.</p>
<h3>Patching BusyBox</h3>
<p>There are several compilation errors at this time should you attempt to run <code>make</code>.</p>
<h4>mount and umount</h4>
<p>We are in luck as there is a patch in <a href="https://github.com/tias/android-busybox-ndk">Tias Guns&#39; repository</a>:</p>
<pre><code class="language-bash">cd /tmp/busybox
wget https://raw.githubusercontent.com/tias/android-busybox-ndk/835af752d00bb025bc8857d92b3af9de7a902cbc/patches/003-mount-umount-fsck-df.patch
patch -N -p1 &lt; 003-mount-umount-fsck-df.patch
</code></pre>
<h4>GNUisms not available...</h4>
<p>We are in luck again as there is a patch in <a href="https://github.com/tias/android-busybox-ndk">Tias Guns&#39; repository</a>:</p>
<pre><code class="language-bash">cd /tmp/busybox
wget https://raw.githubusercontent.com/tias/android-busybox-ndk/835af752d00bb025bc8857d92b3af9de7a902cbc/patches/012-mempcpy.patch
patch -N -p1 &lt; 012-mempcpy.patch
</code></pre>
<h3>Let&#39;s build</h3>
<p>All it should take now is:</p>
<pre><code class="language-bash">make

# Let&#39;s verify it all went fine:
#
#     file busybox
#
# The output should be identical to:
#
#     busybox: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped
</code></pre>
<h3>Get BusyBox on the MeMO Pad</h3>
<h4>Prerequisites</h4>
<p>In order to be able to copy the new <code>busybox</code> binary to the tablet, we need to enable USB debugging.</p>
<ul>
<li>Open <em>Settings</em> &gt; <em>About</em> &gt; <em>Software Information</em></li>
<li>Tap continuously on <em>Build number</em> until you turn Developer mode on</li>
<li>Re-open <em>Settings</em> &gt; <em>Developer options</em></li>
<li>Enable <em>USB debugging</em></li>
</ul>
<h5>udev rules</h5>
<p>Connect the MeMO Pad to your computer. You will get prompted to authorise the connection on the tablet -- accept after reviewing.</p>
<p>You may then discover that you haven&#39;t got permissions to access the tablet using <code>adb</code>. To verify the device is recognised:</p>
<pre><code class="language-bash"># If you don&#39;t have adb installed:
#
#     sudo apt-get install -y android-tools-adb

adb kill-server
adb devices
</code></pre>
<p>If you see lots of question signs under the device name (e.g., <code>????????</code>), we need to do one last thing -- configure the correct permissions when hot-plugging. With the tablet still connected to the computer:</p>
<pre><code class="language-bash">lsusb

# Review the list of attached devices and locate the ASUS MeMO Pad.
# Copy the string after &quot;ID &quot; and paste it in place of the `$REPLACE_ME` variable below.
# The line should look something like:
#
#     export MEMOPAD_ID=&quot;0b05:5507&quot;

export MEMOPAD_ID=&quot;$REPLACE_ME&quot;

echo -e &#39;# ASUS MeMO Pad 7 (ME176C):\nSUBSYSTEM==&quot;usb&quot;, ATTRS{idVendor}==&quot;&#39;${MEMOPAD_ID%:*}&#39;&quot;, ATTRS{idProduct}==&quot;&#39;${MEMOPAD_ID#*:}&#39;&quot;, MODE=&quot;0664&quot;, GROUP=&quot;plugdev&quot;&#39; | sudo tee -a /etc/udev/rules.d/60-android.rules

sudo udevadm control --reload-rules
sudo service udev restart
</code></pre>
<p>Unplug and plug the MeMO Pad. Verify the question signs have disappeared and the device is recognised correctly.</p>
<h4>Push BusyBox to the MeMO Pad</h4>
<pre><code class="language-bash">cd /tmp/busybox
adb push ./busybox /sdcard/
</code></pre>
<p>The binary is on the tablet now, but it requires executable permissions. Use <code>adb</code> to start a shell:</p>
<pre><code class="language-bash"># On your computer:
adb shell

# You will find yourself logged as a regular user on the MeMO Pad.
# To be able to set executable permissions, you need to gain root access:
su

# Approve the request in SuperSU.

# Copy the binary to a new location where we can make it executable.
#
# NOTE: mv does not work and will report &#39;Cross-device link&#39; failure, hence we use cp instead:
cp /sdcard/busybox /data/local/busybox-1.23.0

# Modify the binary permissions to make it executable:
chmod 555 /data/local/busybox-1.23.0

exit

# We are now back logged as a regular user on the MeMO Pad
exit

# On your computer let&#39;s verify it all went fine:
adb shell /data/local/busybox-1.23.0 | head -n1

# The output should be identical to:
#
#     BusyBox v1.23.0 (2015-01-03 12:55:15 UTC) multi-call binary.
</code></pre>
<p>Happy hacking!</p>
]]></description>
    </item>
    <item>
      <title>Day X: Giving up on Firefox OS</title>
      <link>https://blog.angeloff.name/post/2014/10/07/dayx-giving-up-on-firefox-os/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2014/10/07/dayx-giving-up-on-firefox-os/</guid>
      <pubDate>Tue, 07 Oct 2014 19:45:00 GMT</pubDate>
      <description><![CDATA[<h3>The Experiment</h3>
<p>I recently decided to give Firefox OS a try and ordered a <a href="https://developer.mozilla.org/en-US/Firefox_OS/Developer_phone_guide/Flame">Flame</a> developer reference phone. This will be an attempt at a blog series capturing my first 30 days of usage. I will do my best to blog as frequently as I can, usually once or twice a week as I get more accustomed to the new platform.</p>
<h3>The Experience (or lack thereof)</h3>
<p>Going back to the end of August, I was pretty excited to be getting an upgrade from an old and dying Android-based phone to the Flame running Firefox OS, the fresh and exciting OS. My enthusiasm was cooled down fairly quickly once I discovered the OS is still pretty much unfinished and had many bugs. Shortly thereafter a got a Twitter mention saying I should be trailing Firefox OS 2.x as it will offer a much better experience. What did I have to lose, I obviously wasn&#39;t happy with the stock 1.3 version?</p>
<p>So one day I got my USB cable, flashed the phone with Firefox OS 2.1 and started over. No apps, no contacts, no accounts... a clean slate.</p>
<h4>Bugs, bugs, bugs</h4>
<p>I was hoping Firefox OS would be pretty stable after reaching version 2.x when it comes to be basics. Things like making or picking up a phone call surely must be tested with each code change introduced? Automated tests, CI, etc.? I was unpleasantly surprised to find out that this is not the case. The dialer, for example, broke fairly frequently making it impossible to make a phone call. To this day I can&#39;t answer incoming calls as well, the slider to pick up does not work. The latter one has persisted across multiple OS updates.</p>
<p>Is it the case that there are automated tests and bugs have been caught and ignored? If so, why are such changes allowed to be accepted to the nightlies [1] before being finished?</p>
<p>Another annoying issue is the low output volume you get when you plug-in earphones. It will just not go any higher than 10-20% no matter what the UI says. As you unplug your earphones the phone then goes into <em>party-mode</em> with the built-in speaker tearing itself at 100%.</p>
<p>Then there is the network time bug. The phone never correctly synchronises its clock with the network. On Android, connected to the same network, resetting the date &amp; time and then syncing from the network always works. On Firefox OS you get a random date, usually within the past 3-4 days, and a random time. Needless to say this wreaks havoc in pretty much all apps, from the Call Log, to Messaging and E-mail. Just as an example, a missed call from 5 minutes ago may be shown several swipes down with calls from yesterday.</p>
<p>The list goes on and the above is just a fraction of the really frustrating ones. The OS feels like an experiment that is largely unfinished.</p>
<p><small>[1] I get that nightlies are meant for testing, however introducing unfinished changes seems like a bad practise. Firefox recently introduced <a href="https://wiki.mozilla.org/Electrolysis">Electrolysis</a>, a big change <em>to run web content in a separate process from Firefox itself</em>. This was turned off by default and is a good model to follow &ndash; if an update is unfinished or breaks things, hide it behind a flag.</small></p>
<h4>Battery</h4>
<p>Power consumption on the phone is what you would expect it to be and the battery can last you for a good 24 hours with low to moderate usage. That is by no means great, however at this price range is to be expected.</p>
<p>There is a nasty bug, though, which sometimes prevents the phone from charging. I thought charging would have been handled at the hardware level, however the OS appears to have control over this. A restart usually helps.
If you are using a non-standard charger, the phone would sometimes get stuck at the boot screen and begin to vibrate. This doesn&#39;t happen every time and a restart usually helps.</p>
<h4>Marketplace</h4>
<p>If I have to sum it up in one word: poor. Apps are rarely polished and you get wrappers around a website&#39;s mobile version. A good example is Soundcloud which is just m.soundcloud.com behind a pretty icon. As you switch away from the app, the music stops. So yeah, no Soundcloud on the background whilst composing your super important e-mails.</p>
<h4>Core Applications</h4>
<p>In the month that I have been using 2.x Calendar never did work. E-Mail still can&#39;t open or forward attachments. Firefox, the built in browser, has gotten somehow worse. I still haven&#39;t figured out how to use tabs.</p>
<p>There is a handy &#39;Usage&#39; app which is supposed to track your mobile data plan usage. For me it rarely works and reports there is no SIM inserted the majority of the time.</p>
<p>For whatever reason you now also get a global &#39;Search the web&#39; box at the top which is a shortcut to Firefox. It picks up on the app and will change appearance. You would be fooled to think it&#39;s actually part of the app itself, but it isn&#39;t. I can&#39;t remember how many times I&#39;ve tried to look up contacts in the wrong search box.</p>
<h4>Developers, developers, developers</h4>
<p>It&#39;s a shame the platform is so unappealing. I was not once tempted to fire up Vim and work on an app exclusively for Firefox OS. This is part of the problem the platform has &ndash; HTML5 apps are good enough and you don&#39;t go the extra mile to add polish for Firefox OS.</p>
<h3>The Conclusion</h3>
<p>I have made up my mind. It pains me to say I will be going back to Android. Firefox OS is not ready for the end-user and it&#39;s not appealing to me as a developer. It has it&#39;s place in emerging markets, but once you compare it to anything else it doesn&#39;t stand a chance.</p>
<p>The logical question to ask is then <em>can you fix the ugly and the broken</em>? You most probably can but it will take discipline.</p>
<ul>
<li>Don&#39;t ship broken code globally, never, not even in nightlies. If you are asking developers to create apps for your platform, they must have confidence in how reliable it is.</li>
<li>If you introduced an issue by accident, fix it as quickly as you can. Bugzilla is filled with cases of Firefox browser bugs being open for 5+ years. Is history going to repeat itself and will Firefox OS suffer from the same fate?</li>
<li>Polish, polish, polish. When I pick up a phone with Firefox OS, I want it to look finished. I don&#39;t want my notifications screen to be filled with double-escaped HTML messages. Yes, &#39;&lt;span&gt;&#39;s actually appear in notifications and that issue hasn&#39;t been fixed in weeks.</li>
</ul>
<p>I will keep my Flame around and will likely come back to revisit Firefox OS in a couple of months. Perhaps then it will be a more mature platform with less teething problems.</p>
]]></description>
    </item>
    <item>
      <title>Day 2-7: Using Firefox OS</title>
      <link>https://blog.angeloff.name/post/2014/09/01/day2-7-using-firefox-os/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2014/09/01/day2-7-using-firefox-os/</guid>
      <pubDate>Mon, 01 Sep 2014 20:30:00 GMT</pubDate>
      <description><![CDATA[<h3>The Experiment</h3>
<p>I recently decided to give Firefox OS a try and ordered a <a href="https://developer.mozilla.org/en-US/Firefox_OS/Developer_phone_guide/Flame">Flame</a> developer reference phone. This will be an attempt at a blog series capturing my first 30 days of usage. I will do my best to blog as frequently as I can, usually once or twice a week as I get more accustomed to the new platform.</p>
<h3>The Bad &amp; Ugly</h3>
<p>In the last week of usage, there have been more bad things than good. This post may come across as negative, but in reality I am satisfied with the phone and OS at its early stage of development.</p>
<h4>Multitasking</h4>
<p>You can switch between apps by holding the &#39;Home&#39; button. The phone will vibrate (cannot be turned off) before displaying apps as &#39;cards&#39;.</p>
<p><a href="/assets/images/2014/09/01/2014-09-01-19-55-05.png" target="_blank"><img src="/assets/images/2014/09/01/2014-09-01-19-55-05.png" alt="The multitasking interface in Firefox OS" style="max-width: 66%; max-height: 360px; border: 1px solid rgba(0, 0, 0, 0.25);"></a></p>
<p>From this interface you can close an app either by tapping on the (x) icon or by flicking the thumbnail from the bottom. Both methods will work only half the time. When it doesn&#39;t work, you open an app from the list at random instead.</p>
<h4>E-Mail</h4>
<p>Let&#39;s start with the most frequently used app... or what used to be the most frequently used app. E-mail is bad at mail. I have noticed a lot of issues around scrolling the contents of an e-mail. It gets so bad, you can&#39;t read your messages after the first paragraph. I still haven&#39;t figured out if attachments are supported at all, there is no way to open them.</p>
<p>Notifications. They pile up on your lock screen if you have multiple accounts and disappear at once when you open the app. They will disappear even if you didn&#39;t look at the account with new messages in it. What is particularly annoying is after you receive a new notification, if you archive or delete the message on your computer, the notification on the phone will persist. So, yeah...</p>
<h4>Call log</h4>
<p>This should be called something else as it doesn&#39;t do what the title suggests. Notifications for missed calls show up on the lock screen, but then are nowhere to be found in the call log. I have had numerous follow-ups from people asking me why I didn&#39;t return their call... what call?! Outgoing calls are rarely logged as well.</p>
<h4>Browser</h4>
<p>Firefox, of course. If you are looking for customisations, you won&#39;t find them, though:</p>
<p><a href="/assets/images/2014/09/01/2014-09-01-19-17-57.png" target="_blank"><img src="/assets/images/2014/09/01/2014-09-01-19-17-57.png" alt="The Settings page in Firefox browser" style="max-width: 66%; max-height: 360px; border: 1px solid rgba(0, 0, 0, 0.25);"></a></p>
<p>You will receive mobile-optimised versions of websites more often than not. In Firefox, unlike Chrome for Android, you cannot spoof the user-agent to request a desktop version instead. You are stuck with whatever the author has chosen to display for mobile devices.</p>
<p>Sharing a link is pre-configured to open up E-mail as if other options do not exist. In doing so, the E-mail app will sometimes get very confused and report &#39;you are not set up to receive e-mail&#39;.</p>
<p>On heavier pages Firefox is <strong>slow</strong>. As you are trying to zoom in a region, the browser will decide to do a reflow. You end up on a random region instead. Opening links, scrolling, etc. generally feels clunky instead of smooth.</p>
<p>Then there&#39;s the overly sensitive issue which makes you navigate to pages just by flicking through an article.</p>
<h4>Twitter</h4>
<p>This app is basically Twitter for Mobile. You&#39;ll get the same experience if you spoof your Chrome user-agent to a mobile device or visit <a href="https://twitter.com">twitter.com</a> in Safari, etc. The only difference is the app supports web activities:</p>
<blockquote>
<p>We’ve also implemented support for a feature unique to Firefox OS: Web Activities. This lets you tweet photos directly out of any app that also supports web activities such as the built-in photos app.</p>
<div align="right"><a href="https://blog.twitter.com/2013/twitter-for-firefox-os">source</a></div></blockquote>
<p>Twitter on Firefox OS is usable, but definitely lacks behind its iOS and Android counterparts. No notifications for mentions, direct messages, etc.</p>
<h4>YouTube</h4>
<p>Just as above, YouTube is nothing more than a wrapper around the mobile version of <a href="http://youtube.com">youtube.com</a>... but actually worse. The app displays a small area at the bottom which is meant to toggle navigation controls for apps which don&#39;t behave correctly.</p>
<p><a href="/assets/images/2014/09/01/2014-09-01-19-46-31.png" target="_blank"><img src="/assets/images/2014/09/01/2014-09-01-19-46-31.png" alt="YouTube app showing a 'black' area at the bottom to toggle implicit navigation controls" style="max-width: 66%; max-height: 360px; border: 1px solid rgba(0, 0, 0, 0.25);"></a> <a href="/assets/images/2014/09/01/2014-09-01-19-48-17.png" target="_blank"><img src="/assets/images/2014/09/01/2014-09-01-19-48-17.png" alt="YouTube app with expanded implicit navigation controls" style="max-width: 66%; max-height: 360px; border: 1px solid rgba(0, 0, 0, 0.25);"></a></p>
<h3>The Rest</h3>
<p>Next time I&#39;ll be reviewing marketplace apps and sharing more thoughts on the young Firefox OS.</p>
]]></description>
    </item>
    <item>
      <title>Day 1: Setting Up (Firefox OS series)</title>
      <link>https://blog.angeloff.name/post/2014/08/26/day1-setting-up/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2014/08/26/day1-setting-up/</guid>
      <pubDate>Tue, 26 Aug 2014 20:30:00 GMT</pubDate>
      <description><![CDATA[<h3>The Experiment</h3>
<p>I recently decided to give Firefox OS a try and ordered a <a href="https://developer.mozilla.org/en-US/Firefox_OS/Developer_phone_guide/Flame">Flame</a> developer reference phone. This will be an attempt at a blog series capturing my first 30 days of usage. I will do my best to blog as frequently as I can, usually once or twice a week as I get more accustomed to the new platform.</p>
<h3>Mobile Data, voice mail, etc.</h3>
<p>I started playing with the phone and was surprised to find it had managed to auto-configure mobile data (APN access), voice mail, MMS, etc. I am guessing this is largely dependant on the mobile carrier, but I am glad Firefox OS picked up on those. In the past, when dealing with Android, I&#39;ve had to go through long Customer Support calls to receive the correct settings for my device as text messages.</p>
<h3>E-Mail</h3>
<p>The very first app I launched was E-Mail. Unlike Android, Firefox OS does not have a notion of system-wide accounts. Setting up mailboxes is, therefore, specific to the Mail app.</p>
<p><a href="/assets/images/2014/08/26/2014-08-27-19-13-28.png" target="_blank"><img src="/assets/images/2014/08/26/2014-08-27-19-13-28.png" alt="'New Account' screen in Mail" style="max-width: 66%; max-height: 360px; border: 1px solid rgba(0, 0, 0, 0.25);"></a></p>
<p>I use <a href="http://www.google.com/enterprise/apps/business/">Google Apps for Business</a> with <a href="https://www.google.com/landing/2step/">two-factor authentication</a> and was curious if the app will pick up on that. I entered my work e-mail, my regular password and after a little while was prompted to use an &#39;application-specific password&#39;. I created one in my Google security profile and Mail was then able to fully set up the account, incl. IMAP and SMTP over SSL/TLS.</p>
<p>Using Mail has been a bit of a pain. There is no easy way to archive e-mails. I&#39;m still unsure how message deletion is handled, are they sent to the Bin? Drafts are stored locally and if you wish to continue writing on a different device, your best bet is to e-mail the draft to yourself. Handling multiple accounts is a pain and switching between them is 4 taps away. Gmail accounts are set up using IMAP and as such you will get notifications of new messages with a delay (poll interval configurable, no push notifications). I haven&#39;t figured out how to open attachments yet.</p>
<p>Overall, using Mail on Firefox OS feels like a step backwards... a big one at that.</p>
<h3>Calendar</h3>
<p>As before, setting up accounts is specific to the app. When adding calendars from Google, you&#39;ll be sent to the Google profile log in page where you&#39;ll have to enter your full e-mail address and password. If using two-factor authentication, you&#39;ll have to enter the temporary PIN as well. This is different from setting up accounts on E-Mail where application-specific passwords are required.</p>
<p><a href="/assets/images/2014/08/26/2014-08-27-19-32-25.png" target="_blank"><img src="/assets/images/2014/08/26/2014-08-27-19-32-25.png" alt="The default view in Calendar" style="max-width: 66%; max-height: 360px; border: 1px solid rgba(0, 0, 0, 0.25);"></a></p>
<p>The default month view doesn&#39;t leave a lot of space for any events to be shown at the bottom. There are no animations, transitions or any other niceties. For example, in week view swiping from any edge will move a week forward/backward. The new events replace old ones and sometimes it&#39;s difficult to tell if anything changed. In day view the unnecessary big font size cuts event titles rather short and makes landscape view preferred... which does not work.</p>
<p>I rarely use the calendar on my phone and I have a feeling I&#39;ll be using less of it in the future.</p>
<h3>Contacts</h3>
<p>This should come as no surprise, importing contacts is app-specific. You must go through the process of logging into your Google profile once again. Furthermore, I couldn&#39;t find an option to sync with Google so importing is a one-off thing. Yes, it feels a lot like owning an ancient Nokia phone and importing from SIM.</p>
<h3>Summary</h3>
<p>The experience hasn&#39;t been great so far and the stock apps are disappointing. However, given we are talking about Firefox OS 1.4, it is too early to judge. The platform is open so anyone can contribute and improve.</p>
<p>Next time I&#39;ll be setting up Twitter and apps I use frequently.</p>
]]></description>
    </item>
    <item>
      <title>Day 0: Flame Unboxing</title>
      <link>https://blog.angeloff.name/post/2014/08/25/day0-flame-unboxing/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2014/08/25/day0-flame-unboxing/</guid>
      <pubDate>Mon, 25 Aug 2014 20:30:00 GMT</pubDate>
      <description><![CDATA[<h3>The Experiment</h3>
<p>I recently decided to give Firefox OS a try and ordered a <a href="https://developer.mozilla.org/en-US/Firefox_OS/Developer_phone_guide/Flame">Flame</a> developer reference phone. This post and the ones following will be an attempt at a blog series capturing my first 30 days of usage. I will do my best to blog as frequently as I can, usually once or twice a week as I get more accustomed to the new platform.</p>
<h3>Why a Firefox OS-based device?</h3>
<p>I have been a long-time Android user (and recently an iPhone user by accident). I own a <a href="http://www.gsmarena.com/samsung_i9000_galaxy_s-3115.php">Samsung Galaxy S I</a> phone which I have been successfully patching to the latest Android version using <a href="http://www.cyanogenmod.org/">Cyanogenmod</a>. During the years, however, I have owned all the successors to the original Galaxy S. My wife owns a <a href="http://www.gsmarena.com/samsung_i9190_galaxy_s4_mini-5375.php">Galaxy S4 mini</a> and seems happy with it.</p>
<p>Although in the past patching has worked reasonably well, recent versions of Android are too demanding of the ancient hardware I was using. This prompted me to look around for a new phone. After a lot of soul-searching, I decided I don&#39;t want yet another Android-based phone. I was ready for something new, open and extensible.</p>
<p>I still have an <a href="http://en.wikipedia.org/wiki/HP_TouchPad">HP TouchPad</a> lying around the flat which dual-boots into Android and <a href="http://en.wikipedia.org/wiki/WebOS">webOS</a>. I believe web-based OS&#39;es that embrace open and modern technologies are the way to go. So... what options do I have?</p>
<h4>The Flame developer reference phone</h4>
<p>As soon as Mozilla made the <a href="https://hacks.mozilla.org/2014/05/flame-firefox-os-developer-phone/">announcement</a>, I knew I wanted to own a Flame device. It&#39;s a mid-tier phone which runs the latest Firefox OS. An OS that I might actually like... and with prices as low as £100 it&#39;s a great value for money.</p>
<p>If you haven&#39;t seen the specs, here&#39;s a quote from the announcement:</p>
<blockquote>
<p>Qualcomm MSM8210 Snapdragon, 1.2GHZ Dual core processor
4.5” screen (FWVGA 854×480 pixels)
Cameras: Rear: 5MP with auto-focus and flash / Front: 2MP
Frequency: GSM 850/900/1800/1900MHz
UMTS 850/900/1900/2100MHz
8GB memory, MicroSD slot
256MB – 1GB RAM (adjustable by developer)
A-GPS, NFC
Dual SIM Support
Battery capacity: 1,800 mAh
WiFi: 802.11 b/g/n, Bluetooth 3.0, Micro USB</p>
</blockquote>
<h3>A word of caution</h3>
<p>The Flame phone as ordered from <a href="http://www.everbuying.com/product549652.html">Everbuying</a> ships from Singapore (manufactured in China). If you are shipping to a EU member country, your order may be subject to import taxes. Depending on where you live, you may also need to provide proof-of-payment as the supplier will likely declare your order as &#39;no commercial value&#39; (which is a red flag for customs). Bring your PayPal receipt or wire transfer papers with you.</p>
<h2>Unboxing, please!</h2>
<p>Right, let&#39;s get on with it, shall we?</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1132.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1132.jpg" alt="The Flame phone box with T2Mobile label at the front" style="max-width: 33%; max-height: 180px;"></a> <a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1133.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1133.jpg" alt="The Flame phone box at a slightly different angle" style="max-width: 33%; max-height: 180px;"></a> <a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1134.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1134.jpg" alt="The Flame phone box up-close" style="max-width: 33%; max-height: 180px;"></a></p>
<p>As the phone arrived, it had the T<sup>2</sup>Mobile logo at the front. Wat?</p>
<blockquote>
<p>Mozilla worked closely with T2Mobile in creating the phone, which offers developers a means of configuring the RAM of the handset using the phone&#39;s software so they can emulate a variety of Firefox OS devices that will be released throughout the coming year.</p>
<p>T2Mobile will also be charged with rolling out the software updates of Firefox OS, and even offer you a means of trying out different release channels, so that you can even install nightly builds right from your device.</p>
<div align="right"><a href="http://www.t2mobile.com/index.php?r=section/article&id=53">source</a></div></blockquote>
<p>Mystery solved.</p>
<p>The box itself is nothing to marvel at. It&#39;s plain, it&#39;s simple and the only interesting element to it is the orange screen of the phone illustration. It also feels very light.</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1135.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1135.jpg" alt="The other side of the Flame phone box showing the device specs" style="max-width: 66%; max-height: 360px;"></a></p>
<p>Once you turn the box, the back reveals the phone specs and what&#39;s included in the box.</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1136.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1136.jpg" alt="The box unwrapped showing the front of the Flame phone" style="max-width: 33%; max-height: 180px;"></a></p>
<p>The box opens and reveals the front of the phone. Nothing fancy here, you&#39;ve got your screen protective cover that peels off and an access to the bottom half of the box.</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1139.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1139.jpg" alt="The back of the Flame phone" style="max-width: 33%; max-height: 180px;"></a> <a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1140.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1140.jpg" alt="The full back of the Flame phone" style="max-width: 33%; max-height: 180px;"></a></p>
<p>The back of the phone reveals a slot for an SD card and two SIM cards (2G+3G). The phone OS itself allows you to choose which one will be used for calls, mobile data, etc. The battery is not inserted into the phone at this point.</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1141.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1141.jpg" alt="The contents of the bottom half of the Flame phone box" style="max-width: 33%; max-height: 180px;"></a></p>
<p>The bottom half of the box contains the phone&#39;s back cover, micro-USB cable and earphones (quality not tested).</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1144.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1144.jpg" alt="The full contents of the Flame phone box" style="max-width: 33%; max-height: 180px;"></a> <a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1145.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1145.jpg" alt="The label on the battery which reads 'alcatel onetouch'" style="max-width: 33%; max-height: 180px;"></a></p>
<p>The full contents of the box. The Firefox OS sticker is a nice addition.</p>
<p>A close-up of the battery reveals a label &#39;alcatel onetouch&#39;. My best guess is the Flame phone is a modification of the <a href="http://www.gsmarena.com/alcatel_one_touch_fire-5319.php">Alcatel One Touch Fire</a> and they didn&#39;t spend the time to re-brand the battery. So Mozilla teams up with T<sup>2</sup>Mobile to bring us an Alcatel One Touch Fire variation that has &#39;ThunderSoft (R)&#39; as a boot screen... feels like a Frankenstein&#39;s creation.</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1147.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1147.jpg" alt="The first welcome screen of Firefox OS, selecting a language" style="max-width: 33%; max-height: 360px;"></a> <a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1148.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1148.jpg" alt="The second welcome screen of Firefox OS, selecting a wi-fi network" style="max-width: 33%; max-height: 360px;"></a></p>
<p>With the battery in place, I accidentally held the phone at the top which prompted a boot. The OS was fairly quick to start (and so are subsequent reboots). The first-time use screens prompt to select a language and a wi-fi network. English (UK) is not an option.</p>
<hr>
<p><a href="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1150.jpg" target="_blank"><img src="/assets/images/2014/08/25/day0-flame-unboxing/DSC_1150.jpg" alt="The phone's homescreen after first-time set up" style="max-width: 33%; max-height: 180px;"></a></p>
<p>...and there we have it, a working Firefox OS on a Flame phone. Time to set up mail, calendar, contacts and all the social goodies one is accustomed to.</p>
]]></description>
    </item>
    <item>
      <title>Epic keyboard layout change mode in Ubuntu</title>
      <link>https://blog.angeloff.name/post/2013/06/26/epic-keyboard-layout-change-mode-in-ubuntu/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2013/06/26/epic-keyboard-layout-change-mode-in-ubuntu/</guid>
      <pubDate>Wed, 26 Jun 2013 08:55:00 GMT</pubDate>
      <description><![CDATA[<p>How often do you use your <code>Caps Lock</code> key? I&#39;ve had it remapped to act as another <code>Ctrl</code> for years, but never actually used it as such. So how about using it for something useful, like keyboard layout switching (e.g., US &lt;-&gt; Bulgarian)?</p>
<p>It&#39;s very common amongst the people I know to map left <code>Ctrl+Shift</code> or <code>Alt+Shift</code> to change keyboard layouts.
However, this can often get in the way especially when working with editors such as Vim or Emacs -- one moment you are typing with Latin letters, next you have <em>magically</em> switched to Cyrillic. You then find yourself having to shift from editing to sorting out whatever has gone wrong.</p>
<p>One more thing. The keyboard layout indicator in your OS -- doesn&#39;t that just waste space? Call me minimalistic, I prefer my screen free of clutter.</p>
<p>How to use the epic keyboard layout change mode:</p>
<ol>
<li>Open <em>System Settings</em>. In Unity or Gnome Shell just look for it in the launcher.</li>
<li>Find the <em>Keyboard</em> applet.</li>
<li>Select <em>Layout Settings</em>.</li>
<li>Select <em>Options...</em> under <em>Layouts</em>.</li>
<li>Customise:<ul>
<li><em>Caps Lock key behaviour</em>: leave at <em>Default</em>.</li>
<li><em>Key(s) to change layout</em>: tick <em>Caps Lock</em> only.</li>
<li><em>Use keyboard LED to show alternative layout</em>: tick <em>Caps Lock</em> only.</li>
</ul>
</li>
</ol>
<p>...and there you have it. Whenever you want to use your alternative layout, press <code>Caps Lock</code> and your keyboard LED indicator should light up indicating you are now typing in a different language.</p>
<p>I just need to find a good use for <code>Num Lock</code> now...</p>
<p>Does this work in other OSes? Let me know in the comments below.</p>
]]></description>
    </item>
    <item>
      <title>Stopping Ubuntu services on startup</title>
      <link>https://blog.angeloff.name/post/2013/04/03/stopping-ubuntu-services-on-startup/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2013/04/03/stopping-ubuntu-services-on-startup/</guid>
      <pubDate>Wed, 03 Apr 2013 20:20:00 GMT</pubDate>
      <description><![CDATA[<p>I have been using Ubuntu since 10.04. I am running 13.04 at present and have undergone numerous distribution upgrades and not a single re-install. As a result, there is quite a lot of cruft accumulated by now. By cruft I mean packages I have had to install in order to complete a particular task and never got around to cleaning them up afterwards. For some odd reason, I still keep the projects that depend on them around so uninstalling is not an option.</p>
<p>A fair share of those packages also install services. For example, <code>[sudo] apt-get install -y apache2</code> sets up a web server which is started on every boot. MySQL, PostgreSQL, MongoDB, etc. all come with startup services which are enabled and run on boot by default (something you would want on a server).
As time went on, boot times had increased and the overall performance of the PC slowed down considerably. You can see how many processes are running at any given time on your machine by using <code>ps -e | wc -l</code>. Most of those would be system process (init, session handling, tty, etc.), however many are also started on boot and you most likely don&#39;t need them running all the time.</p>
<p>Ubuntu uses <a href="http://upstart.ubuntu.com/">Upstart</a> to start tasks and services during boot... but that is not all. There are packages that use the old <a href="https://en.wikipedia.org/wiki/UNIX_System_V">System-V</a> shell initialisation scripts in <code>/etc/init.d</code>.</p>
<p>After searching for a while and getting nowhere, I reverted to reading the Upstart documentation in order to find the best way to stop a service. It turns out there is a <a href="http://upstart.ubuntu.com/cookbook/#manual">quick way</a> to keep the job files around (in case you want to start something manually after logging in), but prevent the service from running at boot.</p>
<p>I came up with a combined script which deals with both SysV-style scripts as well as Upstart jobs. The script will attempt to disable a service while preserving the initialisation scripts so you can still <code>[sudo] service name start</code> when you need it.</p>
<p>My results were more than impressive. On a system with an <a href="http://en.wikipedia.org/wiki/Solid-state_drive">SSD</a> disk my boot times improved noticeably which was unexpected. I had some of the most common packages for a developer installed so I used:</p>
<pre><code class="language-shellsession">$ service-disable.sh apache2 lxc lxc-net memcached mongod mongodb mysql palm-novacomd postfix postgresql qemu-kvm
</code></pre>
<p>To find out what services you have on your system, use the following command:</p>
<pre><code class="language-shellsession">$ sudo find /etc/init /etc/init.d \! -iname &#39;*.override&#39; \! -name &#39;.*&#39; | \
  xargs -l basename | \
  sed -e &#39;s/\.conf$//&#39; | \
  sort -u
</code></pre>
<p>Onto the script itself:</p>
<pre><code class="language-bash">#!/bin/sh

# Abort immediately if any command exists with a non-zero code.
set -e

# Do we need &#39;sudo&#39;?
sudo=
if [ &quot;$( id -u )&quot; != 0 ]; then
  sudo=&#39;sudo&#39;
fi

# Parse command-line options.
while getopts &#39;h&#39; option; do
  case &quot;$option&quot; in
    h)
      cat &lt;&lt;-HELP
Usage:
  $( basename &quot;$0&quot; ) [...OPTIONS] [...service]

Options:
  -h       Print script usage and exit.

Arguments:
  service  The service name, e.g., &#39;apache2&#39;, &#39;mysql&#39;, etc.
HELP
      exit 1
      ;;
  esac
done

# Drop parsed options from script input.
shift $((OPTIND-1))

# Ensure we can manage services and System-V init scripts.
if ! which service 1&gt;/dev/null 2&gt;&amp;1 || ! which update-rc.d 1&gt;/dev/null 2&gt;&amp;1; then
  echo &#39;[WARN] You need to be running a Debian-based system with System-V support.&#39; 1&gt;&amp;2
  echo &#39;[WARN] Aborting before any real damage is done.&#39; 1&gt;&amp;2
  exit 1
fi

for service in &quot;$@&quot;; do
  # Stop the service, if it&#39;s running.
  echo -n &quot;[STOP]    &#39;$service&#39;... &quot;
  $sudo service &quot;$service&quot; stop 1&gt;/dev/null 2&gt;&amp;1 || :
  echo &#39;OK&#39;

  # If the legacy System-V style init script is used, purge it from the system.
  # The file remains in /etc/init.d/, but not in any of /etc/rcN.d/ so the service won&#39;t start on boot.
  echo -n &quot;[DISABLE] &#39;$service&#39; rc.d initscript... &quot;
  $sudo update-rc.d -f &quot;$service&quot; remove 1&gt;/dev/null
  echo &#39;OK&#39;

  # If Upstart is used, use an override to set the service job in &#39;manual&#39; mode.
  # See http://upstart.ubuntu.com/cookbook/#manual
  if [ -f &quot;/etc/init/${service}.conf&quot; ]; then
    echo -n &quot;[DISABLE] &#39;$service&#39; Upstart script... &quot;
    if ! grep &#39;manual&#39; &quot;/etc/init/${service}.override&quot; 1&gt;/dev/null 2&gt;&amp;1; then
      echo &#39;manual&#39; | $sudo tee -a &quot;/etc/init/${service}.override&quot; 1&gt;/dev/null
    fi
    echo &#39;OK&#39;
  fi
done
</code></pre>
<p>Download using the <a href="https://gist.github.com/StanAngeloff/4434953/raw/service-disable.sh">raw</a> link, <code>chmod +x service-disable.sh</code> and put somewhere on your <code>$PATH</code>. <code>/usr/local/bin/</code> is usually the right place.</p>
<p><strong>NOTE</strong>: Be extremely careful what services you disable. Make sure you are absolutely certain the service being stopped is not essential for the operation of your PC.</p>
<p>Let me know if your boot times improve.
Feel free to post a (common) service in the comments below if I have missed it in the post itself.</p>
]]></description>
    </item>
    <item>
      <title>Ubuntu 12.04 - Super key not working in shortcuts</title>
      <link>https://blog.angeloff.name/post/2012/08/08/ubuntu-12-04-super-key-not-working-in-shortcuts/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/08/08/ubuntu-12-04-super-key-not-working-in-shortcuts/</guid>
      <pubDate>Wed, 08 Aug 2012 12:00:00 GMT</pubDate>
      <description><![CDATA[<p>If you are running the latest Ubuntu this Summer and are trying to configure your keyboard shortcuts to use the <code>Super</code> key, you may be out of luck.</p>
<p>Up until recently, I was quite happy with my <code>Super+E</code> key launching <code>nautilus</code> in my home directory. I went to <em>Keyboard Shortcuts</em> and played around with the configuration and then restored my original values. To my surprise, I could no longer open <code>nautilus</code> with the key combination <code>Super+E</code>.
It took me all evening to find a solution and as it turns out, there are several issues at play:</p>
<ul>
<li><p>If you haven&#39;t mapped your <code>Super</code> key yet, you are <a href="http://askubuntu.com/a/138136/49686">advised to do so</a> before you continue.</p>
</li>
<li><p>There is a <a href="https://bugs.launchpad.net/ubuntu/+source/unity/+bug/704231">long standing issue with multiple regressions</a> where <em>Unity</em> is blocking any other apps from receiving the <code>Super</code> key if the Dash is configured to open just by using that key. You should set it to a key combination, e.g., <code>Super+L</code> or similar.</p>
</li>
<li><p>The latest regression <a href="https://bugs.launchpad.net/ubuntu/+source/gnome-settings-daemon/+bug/950160">Unity blocks other programs from binding globally to Super+_ or Alt+_ (* = any key)</a> has been fixed, but not officially released.</p>
</li>
</ul>
<p>So, at the end, it turns out it&#39;s <code>gnome-settings-daemon</code> being faulty. To get the updated version, which should fix the issue on Ubuntu 12.04, you need to accept packages from the <a href="https://wiki.ubuntu.com/Testing/EnableProposed"><code>proposed</code></a> archive.</p>
<p>Start by making sure you have your system up-to-date:</p>
<pre><code class="language-shellsession">$ sudo apt-get update
$ sudo apt-get dist-upgrade
# Accept upgrades, if any.
</code></pre>
<blockquote>
<p>To enable the proposed archive for Ubuntu 12.04 go to <strong>Applications→Ubuntu Software Center→Edit→Software Sources→Updates</strong> and ensure that <strong>precise-proposed</strong> is ticked.</p>
</blockquote>
<p>You should also make sure to suppress updates you are not interested in as you may unnecessarily install an unstable package. To opt-out of automatic updates from the <code>proposed</code> archive, create a new file under <code>/etc/apt/preferences.d/precise-proposed</code> and put the following inside it:</p>
<pre><code class="language-text">Package: *
Pin: release a=precise-security
Pin-Priority: 990

Package: *
Pin: release a=precise-updates
Pin-Priority: 900

Package: *
Pin: release a=precise-proposed
Pin-Priority: 400
</code></pre>
<p>What the above file does is to ensure the <code>proposed</code> packages are lower in priority than their stable versions from <code>precise-updates</code>.
Before you continue, make sure you don&#39;t have any package updates. If you do, it means something was picked up from the <code>proposed</code> archive and this should not have happened:</p>
<pre><code class="language-shellsession">$ sudo apt-get update
$ sudo apt-get dist-upgrade
# Confirm you have 0 upgrades.
</code></pre>
<p>Finally, install <code>gnome-settings-daemon</code> from <code>precise-proposed</code>:</p>
<pre><code class="language-shellsession">$ sudo apt-get install gnome-settings-daemon/precise-proposed
</code></pre>
<p>Unfortunately you would likely need to restart the system for changes to take effect. In my case I <code>kill</code>ed the daemon, but in the process it didn&#39;t reload with the correct settings and I experienced a nasty crash.</p>
<p>I hope changes would be pushed to stable channels soon which would make this post obsolete, but in the interim, enjoy your <code>Super</code> key combos working again.</p>
]]></description>
    </item>
    <item>
      <title>PHP Recursive Patterns</title>
      <link>https://blog.angeloff.name/post/2012/08/05/php-recursive-patterns/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/08/05/php-recursive-patterns/</guid>
      <pubDate>Sun, 05 Aug 2012 13:30:00 GMT</pubDate>
      <description><![CDATA[<p><em><strong>tl;dr;</strong> This post deals with writing very simple parsers for nested data using recursive regular expressions.</em></p>
<p>There is a very good reason why regular expressions are called that -- they are regular. You can get a lot done with them, but if your data has a complex structure, you&#39;d often be advised to use a parser.
A good example is processing data where parentheses can be nested. A simple regular expression:</p>
<pre><code class="language-php">/\([^\)]+/
</code></pre>
<p>fails quickly when a nested <code>(</code> <code>)</code> pair is encountered.</p>
<pre><code class="language-php">&lt;?php

$string = &#39;(Hello (World!))&#39;;
preg_match_all(&#39;/\([^\)]+/&#39;, $string, $groups);
var_export($groups);

# array (
#   0 =&gt; array (
#     0 =&gt; &#39;(Hello (World!&#39;,
#   ),
# )
</code></pre>
<p><a href="http://www.pcre.org/">PCRE</a> (the regular expressions engine behind <a href="http://www.php.net/manual/en/ref.pcre.php"><code>preg_*</code> functions</a>) has support for dealing with those cases where you need to recurse and repeat the pattern.
For example, a very simple CSS parser would need to balance opening <code>{</code> and closing <code>}</code>, i.e., taking into account <code>@media</code> queries also enclosed by a <code>{..}</code> pair. Let&#39;s assume this document:</p>
<pre><code class="language-css">body {
  color: #888;
}

@media print {
  body {
    color: #333;
  }
}

code {
  color: blue;
}
</code></pre>
<p>A non-<a href="http://www.regular-expressions.info/repeat.html#greedy">greedy</a> regular expression like <code>/{.*?}/</code> would fail as it exits as soon as a closing <code>}</code> is encountered resulting in the following captured groups:</p>
<pre><code class="language-php">array (
  0 =&gt; &#39;{ color: #888; }&#39;,
  1 =&gt; &#39;{ body { color: #333; }&#39;,  # NOTE: the first opening { is not balanced.
  2 =&gt; &#39;{ color: blue; }&#39;,
)
</code></pre>
<p>To deal with balanced pairs, we need a way to descend into a pair and repeat the pattern. In pseudo Basic-like regular expressions code this would mean:</p>
<pre><code class="language-text">10: expect an opening &#39;{&#39;
20:   read until
21:     &#39;{&#39; or &#39;}&#39; is encountered
22:     OR end of data, goto 50.
30:   if &#39;{&#39;, start over; goto 10.
40:   if &#39;}&#39;, goto 50.
50: expect a balanced closing &#39;}&#39;
</code></pre>
<p><a href="http://php.net/manual/en/regexp.reference.recursive.php">PCRE supports <code>(?R)</code></a> which does exactly what is illustrated above: it repeats the <strong>whole</strong> pattern recursively.
Let&#39;s go back to the non-greedy pattern (and the sample CSS document):</p>
<pre><code class="language-php">/{.*?}/
</code></pre>
<p>and modify it so it starts a new group for each nested pair:</p>
<pre><code class="language-php">/
  {           # find the first opening &#39;{&#39;.
    (?:       # start a new group, this is so &#39;|&#39; below does not apply/affect the opening &#39;{&#39;.
      [^{}]+  # skip ahead happily if no &#39;{&#39; or &#39;}&#39;.
      |       #   ...otherwise...
      (?R)    # we may be at the start of a new group, repeat whole pattern.
    )
    *         # nesting can be many levels deep.
  }           # finally, expect a balanced closing &#39;}&#39;
/
</code></pre>
<p>Let&#39;s convert this to an inline pattern and run it against our sample CSS document:</p>
<pre><code class="language-php">&lt;?php

$string = &lt;&lt;&lt;CSS
body { color: #888; }

@media print { body { color: #333; } }

code { color: blue; }
CSS;

$pattern = &#39;/{(?:[^{}]+|(?R))*}/&#39;;

preg_match_all($pattern, $string, $groups);
var_export($groups);

# array (
#   0 =&gt;
#   array (
#     0 =&gt; &#39;{ color: #888; }&#39;,
#     1 =&gt; &#39;{ body { color: #333; } }&#39;,
#     2 =&gt; &#39;{ color: blue; }&#39;,
#   ),
# )
</code></pre>
<p>This is a great start to a simple CSS parser. You can now iterate over the results and run the expression again until you get a flattened list of all the properties.</p>
<p>Note again <code>(?R)</code> repeats the <strong>whole</strong> pattern. If you want to match all <code>@media</code> queries for example, you&#39;d need to make sure the group is optional:</p>
<pre><code class="language-php">&lt;?php

# [...]

$pattern = &#39;/(?:@media[^{]+)?&#39;     # @media is optional, e.g., when we have descended into it.
         . &#39;{(?:[^{}]+|(?R))*}/s&#39;;
</code></pre>
<h3>Why not a parser instead?</h3>
<p>Parsers can be much more complex than a one-line regular expression. You&#39;d most likely also need to include a dependency in your project.
If all you need is a simple solution then I say try and use recursive regular expressions first. I have been hacking on a tool to <a href="https://gist.github.com/3164569">merge <code>@media</code> queries</a> produced by Sass and I got the job done with no complex parsers or dependencies involved.</p>
]]></description>
    </item>
    <item>
      <title>Vim, regular expressions and negative lookahead</title>
      <link>https://blog.angeloff.name/post/2012/08/05/vim-regular-expressions-negative-lookahead/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/08/05/vim-regular-expressions-negative-lookahead/</guid>
      <pubDate>Sun, 05 Aug 2012 13:15:00 GMT</pubDate>
      <description><![CDATA[<p>One of Vim&#39;s biggest strengths IMHO is it&#39;s quick access to the search and <a href="http://vimdoc.sourceforge.net/htmldoc/pattern.html#pattern-multi-items">extended support for regular expressions</a>. It can be very frustrating at first as the syntax for the latter doesn&#39;t follow Perl or anything else I have used (<code>grep</code>, etc.), but once you learn more about it, you&#39;ll start to appreciate it.</p>
<p>A feature I recently discovered was <a href="http://vimdoc.sourceforge.net/htmldoc/pattern.html#/@!">negative lookahead</a>. This can be useful in cases where you are looking for a particular string, but only if it&#39;s not followed by another. In my case, I was looking for all references of <code>include</code>, but since this also matches Ruby&#39;s <code>include?</code>, I wanted to exclude and not report it. The search expression I used was:</p>
<pre><code class="language-vim">/include\(?\)\@!
</code></pre>
<p>There are all sorts of goodness in the <a href="http://vimdoc.sourceforge.net/htmldoc/pattern.html">Vim documentation on patterns</a>. If you are using Vim on a daily basis, it&#39;s worth spending a few minutes to learn what&#39;s available. Your next search &amp; replace could save you hours of editing or recording and getting a macro just right.</p>
]]></description>
    </item>
    <item>
      <title>Quick tab switching in Vim</title>
      <link>https://blog.angeloff.name/post/2012/07/23/quick-tab-switching-in-vim/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/07/23/quick-tab-switching-in-vim/</guid>
      <pubDate>Mon, 23 Jul 2012 12:00:00 GMT</pubDate>
      <description><![CDATA[<p>This is so simple, it doesn&#39;t even deserve an explanation:</p>
<pre><code class="language-vim">nnoremap &lt;silent&gt; &lt;C-J&gt; gt
nnoremap &lt;silent&gt; &lt;C-K&gt; gT
</code></pre>
<p>Re-map your <code>Caps Lock</code> key to <code>Ctrl</code> and navigating around your tabs just got a lot easier.</p>
<p>To re-map in Ubuntu, open up the Dash, find the <em>Keyboard Layout</em> app, launch it, go to <em>Options...</em> and expand <em>Caps Lock key behaviour</em>. Select <em>Make Caps Lock an additional Control but keep the Caps_Lock keysym</em>. Close windows. Changes should be available immediately.</p>
]]></description>
    </item>
    <item>
      <title>Vim plug-ins roundup, tips &amp; tricks</title>
      <link>https://blog.angeloff.name/post/2012/06/28/vim-plug-ins-roundup-tips-tricks/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/06/28/vim-plug-ins-roundup-tips-tricks/</guid>
      <pubDate>Thu, 28 Jun 2012 23:30:00 GMT</pubDate>
      <description><![CDATA[<p>I am fairly new to Vim. <a href="https://github.com/StanAngeloff/komodo-html-toolkit/issues/25#issuecomment-1924790">When I switched editors</a> and moved to Vim completely (about an year ago), I looked around for plug-ins and scripts other Users were using. I knew I was going to improve my text editing speed just by using the core editor itself, however I was more keen on setting up my very own personal environment.</p>
<p>What helped me a great deal were all those <nobr>&#39;<a href="https://google.com/search?q=vim+plug-ins+must+have">Vim plug-ins you MUST have</a>&#39;</nobr>-style articles. After a while, however, they got pretty boring as most were covering the same plug-ins.</p>
<p>As I started using Vim for everything (after an initial period of pain and suffering), I kept expanding my <a href="https://github.com/StanAngeloff/dotfiles/blob/master/.vimrc#files">.vimrc</a> and soon found it had grown to contain a lot of useful and rare gems. My intentions are by sharing these here they would also help you be more productive in your day-to-day tasks in Vim.</p>
<h2>Plug-ins</h2>
<h3><strong><a href="https://github.com/godlygeek/tabular">godlygeek/tabular</a></strong></h3>
<blockquote>
<p>Vim script for text filtering and alignment.</p>
</blockquote>
<p>I like my code well indented and aligned... but it is a pain to keep it organised by hand. Tabular does this instead of you. It is extremely helpful and can deal with any coding style preference you may have. Take, for example, this input:</p>
<pre><code class="language-php">&lt;?php

$hello = &#39;world&#39;;
$how = &#39;are you&#39;;
$when = &#39;today&#39;;
</code></pre>
<p>For quick access to Tabular, set up key bindings like so to trigger indentation on <code>=</code>:</p>
<pre><code class="language-vim">nnoremap &lt;leader&gt;a= :Tabularize /=&lt;CR&gt;
</code></pre>
<p>Pressing <code>\a</code> (where <code>\</code> is the leader key) yields:</p>
<pre><code class="language-php">&lt;?php

$hello = &#39;world&#39;;
$how   = &#39;are you&#39;;
$when  = &#39;today&#39;;
</code></pre>
<p>There, all nice and tidy.</p>
<h3><strong><a href="https://github.com/mattn/zencoding-vim">mattn/zencoding-vim</a></strong></h3>
<blockquote>
<p>Zen-Coding for Vim.</p>
</blockquote>
<p>This one is a must-have for HTML folks. Take this input:</p>
<pre><code class="language-html">ul&gt;li*5&gt;a&gt;span
</code></pre>
<p>Re-map Zen Coding to suit your needs:</p>
<pre><code class="language-vim">let g:user_zen_leader_key = &#39;&lt;leader&gt;z&#39;
</code></pre>
<p>and voila!</p>
<pre><code class="language-html">&lt;ul&gt;
  &lt;li&gt;
    &lt;a href=&quot;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href=&quot;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href=&quot;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href=&quot;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href=&quot;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</code></pre>
<h3><strong><a href="https://github.com/othree/html5.vim">othree/html5.vim</a></strong></h3>
<blockquote>
<p>HTML5 omni-complete and syntax.</p>
</blockquote>
<p>HTML is dead, long live HTML5! This plug-in provides syntax highlighting for the new HTML5 tags which are not available out-of-the-box in a default Vim installation.</p>
<p>It also plays nicely with other plug-ins, such as <a href="https://github.com/StanAngeloff/php.vim">php.vim</a>.</p>
<h3><strong><a href="https://github.com/pangloss/vim-javascript">pangloss/vim-javascript</a></strong></h3>
<blockquote>
<p>Vastly improved JavaScript indentation.</p>
</blockquote>
<p>If you do a lot of JavaScript development, you have probably been driven to despair on each new line. Vim&#39;s default JavaScript syntax file is not very smart when it comes to indentation and it can sometimes be utterly stupid. This plug-in puts a stop to it all.</p>
<h3><strong><a href="https://github.com/samsonw/vim-task">samsonw/vim-task</a></strong></h3>
<blockquote>
<p>Basically, this is the TextMate Tasks Bundle port for Vim.</p>
</blockquote>
<p>I like keeping NOTEs and TODOs in my projects. This is a very simple plug-in which provides syntax highlighting for <code>*.tasks</code> files and a couple of handy key bindings to deal with resolving items.</p>
<p><a href="/assets/images/vim-task.png"><img title="Vim-Task with Monaco font" src="/assets/images/vim-task.png" alt="Vim-Task with Monaco font" width="300"></a></p>
<h3><strong><a href="https://github.com/sjl/gundo.vim">sjl/gundo.vim</a></strong></h3>
<blockquote>
<p>Vim plug-in to visualize your Vim undo tree.</p>
</blockquote>
<p>Undone your changes, tried something different and then realised you want to get your old code back? Gundo comes to the rescue giving you a tree of all edits and points of interest in the history.</p>
<p><a href="http://www.flickr.com/photos/sjl7678/5093114605/" title="gundo by stevelosh, on Flickr"><img src="/assets/images/flickr/gundo.jpg" width="300" alt="gundo" /></a></p>
<h3><strong><a href="https://github.com/vim-scripts/session.vim--Odding">session.vim--Odding</a></strong></h3>
<blockquote>
<p>Extended session management for Vim.</p>
</blockquote>
<p>Restart Vim and avoid losing your editing session. This plug-in saves your Vim sessions and restores them so it is like you never even left Vim. The default options are somewhat intrusive, but it doesn&#39;t take too much to customise the plug-in to behave:</p>
<pre><code class="language-vim">&quot; Don&#39;t prompt on Vim close if we want to save the session.
let g:session_autosave=0
&quot; Don&#39;t auto-load saved sessions on Vim start.
let g:session_autoload=0
&quot; Re-map for easy session saving/restore.
noremap &lt;leader&gt;ss :SaveSession user&lt;CR&gt;
noremap &lt;leader&gt;sr :OpenSession user&lt;CR&gt;
</code></pre>
<p>Whenever you feel you need to close Vim, but want to be able to get back your opened buffers, use <code>\ss</code> (where <code>\</code> is the leader key) before <code>:q</code>uitting. Next time you start Vim, use <code>\sr</code> to restore.</p>
<p>Note you wouldn&#39;t be able to save options like plug-ins state, e.g., opened directories in NERDTree.</p>
<h3><strong><a href="https://github.com/kien/ctrlp.vim">kien/ctrlp.vim</a></strong></h3>
<blockquote>
<p>Fuzzy file, buffer, mru, tag, etc finder.</p>
</blockquote>
<p>When I first got to Vim, I tried <a href="http://www.vim.org/scripts/script.php?script_id=3025">Command-T</a>. I loved it... but having Ruby support available in Vim was proving an issue on some Windows machines. You also need to compile a binary which further meant the plug-in cannot be used out-of-the-box in a new Vim installation.</p>
<p>CtrlP is a great alternative with a slew of new features to offer. You still get a fuzzy matching file finder, but you can also search for tags, recent buffers, etc.</p>
<p>I don&#39;t like having plug-ins register their key bindings without my say, so I turn off the defaults for CtrlP and create personalised mappings:</p>
<pre><code class="language-vim">&quot; Don&#39;t use &lt;C-P&gt;, leave it available for something else.
let g:ctrlp_map=&#39;&#39;

nnoremap &lt;silent&gt; &lt;leader&gt;o :&lt;C-U&gt;CtrlPCurWD&lt;CR&gt;
nnoremap &lt;silent&gt; &lt;leader&gt;b :&lt;C-U&gt;CtrlPBufTag&lt;CR&gt;
</code></pre>
<p>Use <code>\o</code> (where <code>\</code> is the leader key) to fuzzy match and open a file and <code>\b</code> to fuzzy match and move to a tag in the current buffer (quickly navigate to a method, etc.)</p>
<h3><strong><a href="https://github.com/thinca/vim-visualstar">thinca/vim-visualstar</a></strong></h3>
<blockquote>
<p>star for Visual-mode.</p>
</blockquote>
<p>The star <code>*</code> is a very powerful key in Vim. You can quickly look for all occurrences of the word under the cursor, but it is not always a word you&#39;d be looking for. This plug-in extends the star in visual mode so it looks for all occurrences of the entire selected text, taking care of escaping any special characters or whitespace that may have been selected.</p>
<p>IMHO this is how Vim&#39;s <code>*</code> should work by default in visual mode.</p>
<h3><strong><a href="https://github.com/hail2u/vim-css3-syntax">hail2u/vim-css3-syntax</a></strong></h3>
<blockquote>
<p>Add CSS3 syntax support to vim&#39;s built-in <code>syntax/css.vim</code>.</p>
</blockquote>
<p>This plug-in provides syntax highlighting for the new CSS3 properties. It is a bit trickier to set it up so it works for HTML and Sass buffers, but you only have to do it once anyway.</p>
<h3><strong><a href="https://github.com/jesseschalken/list-text-object">jesseschalken/list-text-object</a></strong></h3>
<blockquote>
<p>A Vim script to provide text objects for items in lists like ( a, b, c ), { a; b; c; } etc.</p>
</blockquote>
<p>Lastly, I came across this plug-in several weeks ago and have been using it on a daily basis ever since. It deals with text objects for lists, e.g.:</p>
<pre><code class="language-php">&lt;?php

print implode(&#39;, &#39;, [&#39;Hello&#39;, &#39;World&#39;, &#39;How are&#39; &lt;|&gt;. &#39; you?&#39;]);
</code></pre>
<p>Given the cursor position is defined by <code>&lt;|&gt;</code> above, pressing <code>ci,</code> will result in:</p>
<pre><code class="language-php">&lt;?php

print implode(&#39;, &#39;, [&#39;Hello&#39;, &#39;World&#39;, &lt;|&gt;]);
</code></pre>
<p>This is a great and quick way to change function arguments, list values, etc.</p>
<h2>Tips &amp; Tricks</h2>
<h3><strong>Keep Your Focus</strong></h3>
<p>One of the greatest strengths of Vim is having your hands rest comfortably on the home row whilst you are editing away. It bugged me I can&#39;t do the same with my screen, i.e., focus my attention on a given area and have everything I am working on flow in that particular line of screen. You can achieve this in Vim by setting the <code>scrolloff</code> option to a relatively big value:</p>
<pre><code class="language-vim">set scrolloff=120  &quot; Total LoC visible on screen divided by 2 or higher.
</code></pre>
<p>It takes some getting used to, but eventually (hopefully) you will find there is less strain on your eyes.</p>
<h3><strong>Relative Line Numbers</strong></h3>
<p>I have always found this particular &#39;feature&#39; of Vim to be extremely annoying. That is until I decided to try and live with it for at least a week. Coupled with the technique above, the editor becomes static and all that ever changes is the buffer itself. You can also much more easily navigate to a particular line since you know how many lines away it happens to be.</p>
<pre><code class="language-vim">set rnu  &quot; Show relative line numbers.
</code></pre>
<h3><strong>Long Lines Slow Down Vim</strong></h3>
<p>It has happened to all of us. You accidentally open a minified JavaScript file, Vim crawls to a complete halt and <code>&lt;C-C&gt;</code> cannot get you control of the editor back. This usually happens because Vim is having trouble syntax highlighting long lines. By setting a limit on the characters Vim will highlight per line at most, you can avoid situations like the above.</p>
<pre><code class="language-vim">set synmaxcol=512
</code></pre>
<h3><strong>Dreadful &#39;Ex&#39; mode</strong></h3>
<p><code>Q</code> must be one of the most useless default key bindings in Vim. I have yet to hear someone making extensive use of &#39;Ex&#39; mode. It is much more efficient having <code>Q</code> save and quit the current buffer (and you would also never have to type <code>visual</code> again):</p>
<pre><code class="language-vim">nnoremap &lt;silent&gt; Q ZZ
</code></pre>
<h3><strong>Quick Indentation Settings</strong></h3>
<p>Very often files open with the wrong indentation settings. 2, 4 and 8 are the most common setting for spaces per indent:</p>
<pre><code class="language-vim">&quot; Key bindings for adjusting the tab/shift width.
nnoremap &lt;leader&gt;w2 :setlocal tabstop=2&lt;CR&gt;:setlocal shiftwidth=2&lt;CR&gt;
nnoremap &lt;leader&gt;w4 :setlocal tabstop=4&lt;CR&gt;:setlocal shiftwidth=4&lt;CR&gt;
nnoremap &lt;leader&gt;w8 :setlocal tabstop=8&lt;CR&gt;:setlocal shiftwidth=8&lt;CR&gt;
</code></pre>
<h2>Final Words</h2>
<p>Leave a comment with your favourite, not-so-popular Vim plug-in or script below. Share this article with friends and on Twitter. I hope it has helped you make your Vim a little bit nicer to work from.</p>
]]></description>
    </item>
    <item>
      <title>Ubuntu 12.04 (Precise) &amp; PHP 5.2.x</title>
      <link>https://blog.angeloff.name/post/2012/06/18/ubuntu-12-04-precise-php-5-2/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/06/18/ubuntu-12-04-precise-php-5-2/</guid>
      <pubDate>Mon, 18 Jun 2012 14:12:00 GMT</pubDate>
      <description><![CDATA[<p>If you get lots of:</p>
<pre><code class="language-bash">configure: error: Cannot find libXXX under /usr.
</code></pre>
<p>when you attempt to <code>./configure</code> PHP 5.2.x (and possibly earlier series as well), try appending:</p>
<pre><code class="language-bash">--with-libdir=lib/x86_64-linux-gnu
</code></pre>
<p>This instructs the script to look for libraries under <code>/usr/lib/x86_64-linux-gnu</code> instead of <code>/usr/lib</code>. If this doesn&#39;t work for you, try running:</p>
<pre><code class="language-shellsession">$ sudo updatedb
$ locate &#39;libXXX&#39; | grep &#39;so$&#39;
</code></pre>
<p>Which should output the directory where the binary <code>libXXX</code> (e.g., <code>libmysqlclient</code>) is installed.</p>
<hr>
<p>If you also see this at the linking stage:</p>
<pre><code>ext/openssl/xp_ssl.c: undefined reference to `SSLv2_server_method&#39;
</code></pre>
<p>You would want to patch your 5.2.17 source with <a href="https://bugs.php.net/patch-display.php?bug_id=54736&patch=debian_patches_disable_SSLv2_for_openssl_1_0_0.patch&revision=latest">debian_patches_disable_SSLv2_for_openssl_1_0_0.patch</a>.</p>
]]></description>
    </item>
    <item>
      <title>Ubuntu 12.04 (Precise) light menus</title>
      <link>https://blog.angeloff.name/post/2012/04/28/ubuntu-12-04-precise-light-menus/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/04/28/ubuntu-12-04-precise-light-menus/</guid>
      <pubDate>Sat, 28 Apr 2012 16:55:00 GMT</pubDate>
      <description><![CDATA[<p>The design team at Canonical has decided to refresh the default theme in Ubuntu for its LTS release to feature light menus from light sources and dark menus from dark sources.</p>
<p>If you are anything like me, the decision didn&#39;t probably go well with you either. I&#39;ve been hacking on a &#39;proper&#39; port back to dark menus, those interested can find the <a href="https://github.com/StanAngeloff/AmbianceOneiric">source and instructions</a> available on GitHub.</p>
<p>I&#39;ve <a href="https://github.com/StanAngeloff/AmbianceOneiric/commit/99835042fcf1dc037134b9c7330f905451eccc9d">kept the changes</a> to a minimum so you&#39;d still get all other improvements, such as less prominent controls for windows out of focus.</p>
]]></description>
    </item>
    <item>
      <title>Failed to load module &quot;globalmenu-gtk&quot; after uninstalling gnome-shell</title>
      <link>https://blog.angeloff.name/post/2012/02/06/failed-globalmenu-gtk/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/02/06/failed-globalmenu-gtk/</guid>
      <pubDate>Mon, 06 Feb 2012 17:53:00 GMT</pubDate>
      <description><![CDATA[<p>If you get:</p>
<pre><code class="language-bash">Gtk-Message: Failed to load module &quot;globalmenu-gtk&quot;
</code></pre>
<p>every time you launch an app, you have left a Gnome Shell module, which is no longer present on your system, in your <code>GTK_MODULES</code> environment variable. In my case, I enabled the Global Menu extension in Gnome Tweak Tool and then uninstalled Gnome Shell. To fix, I <code>rm</code>ed the <code>/etc/profile.d/globalmenu.sh</code> file and rebooted.</p>
]]></description>
    </item>
    <item>
      <title>Diff&apos;ing images in Git</title>
      <link>https://blog.angeloff.name/post/2012/02/01/diffing-images-in-git/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/02/01/diffing-images-in-git/</guid>
      <pubDate>Wed, 01 Feb 2012 23:32:00 GMT</pubDate>
      <description><![CDATA[<p>I use Git on the command-line usually, but lately I&#39;m using more and more of <a href="http://cola.tuxfamily.org/">git-cola</a>. It&#39;s compact, keyboard-friendly, regularly updated, features a clean UI with main focus on staging and diffs. It was while working in git-cola merging over 100+ files from two different branches that I discovered quite a few overlapping image files. The diff panel was useless and it&#39;s not like I can rely on the command-line for non-textual diffs. Did what every developer does nowadays when faced with an issue, I googled <em>side-by-side diffs</em>, <em>git diff images</em> and any other combination of words and phrases I could come up. There wasn&#39;t much, if anything, useful that came up in the results so I got to work.</p>
<p>I run Ubuntu and Gtk immediately came to mind. It shouldn&#39;t be too difficult to display the two images with their dimensions side-by-side in a window. I don&#39;t need fancy <a href="https://github.com/blog/817-behold-image-view-modes">image view modes</a>, just having the two images next to each other would give me enough information to decide which one to accept. At the end, having never done any PyGtk programming before, I came up with a 50-line script that does just what I need:</p>
<pre><code class="language-python">#!/usr/bin/env python

# Simple Image Diffs
# ==================
#
# How to Install
# --------------
#
# Download the script somewhere on $PATH as &#39;simple-imagediff&#39; with +x:
#
# $ cd ~/bin
# $ wget -O simple-imagediff https://raw.github.com/gist/1716699/simple-imagediff.py
# $ chmod +x simple-imagediff
#
# Prerequisites
# -------------
#
# The script should work out-of-the box on Ubuntu 11.10. On other OS&#39;es you may
# need to install PIL and Gtk3.
#
# Git Setup
# ---------
#
# In ~/.gitconfig, add:
#
# [diff &quot;image&quot;]
#   command = simple-imagediff
#
# In your project, create .gitattributes file and add (this enables the custom
# diff tool above):
#
# *.gif diff=image
# *.jpg diff=image
# *.png diff=image
#
# Try It
# ------
#
# $ git diff path/to/file.png
#
# NOTE: file.png must be versioned and the working copy must be different.

import os
import sys

import Image

from gi.repository import Gdk, Gtk

class SimpleImageDiffWindow(Gtk.Window):
    def __init__(self, left, right):
        Gtk.Window.__init__(self, title=&quot;Simple Image Diff (%s, %s)&quot; % (left, right))
        self.set_default_size(640, 480)
        align = Gtk.Alignment()
        align.set_padding(10, 10, 10, 10)
        box = Gtk.HBox(homogeneous=True, spacing=10)
        box.add(self._create_image_box(left))
        box.add(self._create_image_box(right))
        align.add(box)
        self.add(align)
        self.resize(1, 1)
        self.set_position(Gtk.WindowPosition.CENTER)

    def _create_image_box(self, image_file):
        box = Gtk.VBox(spacing=10)
        frame = Gtk.Frame()
        image = Gtk.Image()
        image.set_from_file(image_file)
        title = Gtk.Label(label=&quot;W: %dpx  |  H: %dpx&quot; % Image.open(image_file).size)
        frame.add(image)
        box.pack_start(frame, True, True, 0)
        box.pack_end(title, False, False, 10)
        return box

def _halt(message, code):
    sys.stderr.write(&quot;[ERROR] %s\n&quot; % message)
    sys.exit(0 &lt;&lt; code)

def _verify_file_exists(target):
    if not os.path.exists(target):
        _halt(&quot;The file &#39;%s&#39; does not exists.&quot; % target, 2)

if __name__ == &#39;__main__&#39;:
    if len(sys.argv) &lt; 3:
        _halt(&#39;Not enough arguments.&#39;, 1)
    _verify_file_exists(sys.argv[1])
    _verify_file_exists(sys.argv[2])
    app = SimpleImageDiffWindow(sys.argv[1], sys.argv[2])
    app.connect(&#39;delete-event&#39;, Gtk.main_quit)
    app.show_all()
    Gtk.main()
</code></pre>
<img src="https://p.twimg.com/AkkMTtpCMAAtKL8.png" />

<p>It&#39;s not an ultimate solution. It will choke up on large images, it doesn&#39;t handle transparency well and there are no controls like zooming in/out, but it is better than nothing.</p>
<p>Overall, I found the PyGtk documentation very easy to read, there are plenty of tutorials around and the <a href="http://developer.gnome.org/gtk3/3.0/">API reference</a> has all the information one needs.</p>
<p>Tip: in git-cola, <code>&lt;C-D&gt;</code> will open up the configured diff tool for the highlighted file.</p>
]]></description>
    </item>
    <item>
      <title>pacman -Syu barfs error: XYZ: signature is unknown trust</title>
      <link>https://blog.angeloff.name/post/2012/01/24/pacman-syu-barfs-error-xyz-signature-is-unknown-trust/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/01/24/pacman-syu-barfs-error-xyz-signature-is-unknown-trust/</guid>
      <pubDate>Tue, 24 Jan 2012 14:45:00 GMT</pubDate>
      <description><![CDATA[<p>Things kept getting better and better. Following the recent <a href="/post/2012/01/24/not-enough-random-bytes-available/">pacman upgrade</a>, I was now facing issues with regards to package signatures. I had already successfully completed the keyring initialisation and I was a bit stumbled as to what exactly I was doing wrong.</p>
<p>You remember all those <code>/etc/config saved as /etc/config.new</code> messages. Yes, as it turns out these are important. Given you haven&#39;t modified your <code>pacman</code> configuration (perhaps added to the <code>HoldPkg</code> list recently?), you can safely accept the new values:</p>
<pre><code class="language-shellsession">$ [sudo] mv /etc/pacman.conf /etc/pacman.conf.pacprev
$ [sudo] mv /etc/pacman.conf.pacnew /etc/pacman.conf
</code></pre>
<p>Re-run <code>[sudo] pacman -Syu</code> and you are on your way.</p>
]]></description>
    </item>
    <item>
      <title>Not enough random bytes available.</title>
      <link>https://blog.angeloff.name/post/2012/01/24/not-enough-random-bytes-available/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2012/01/24/not-enough-random-bytes-available/</guid>
      <pubDate>Tue, 24 Jan 2012 14:38:00 GMT</pubDate>
      <description><![CDATA[<h3>Please do some other work to give the OS a chance to collect more entropy! (Need more bytes)</h3>
<p>I decided to upgrade <code>pacman</code> on Arch Linux recently. I was advised to run <code>[sudo] pacman-key --init</code> after the update had finished. Sounds simple enough, just one extra command I need to copy -&gt; paste to get me going again. Wrong. It turns out <strong>gpg</strong> will go about generating a very strong key (did not investigate the exact key size). On my not-so-busy machine it would just sit there doing (what would appear as) nothing for hours. To generate entropy, <code>/dev/random</code> <a href="http://sublimated.wordpress.com/2007/08/28/not-enough-random-bytes-available/">is used</a>. I started:</p>
<pre><code class="language-shellsession">$ cat /dev/random
</code></pre>
<p>in a remote session and there was nothing printed on-screen, e.g., nothing was being generated, e.g., no entropy, e.g., no <strong>gpg</strong> joy. What follows is a very ugly hack to speed things up. Keep the above remote connection open and connect to the machine in a separate tab/window. Start <code>pacman-key</code> as instructed earlier. Leave the window/tab open and connect again, in a third, separate window/tab. Repeat (many) times:</p>
<pre><code class="language-shellsession">$ ls -R /
$ [sudo] sync
$ sudo tee /proc/sys/vm/drop_caches &lt;&lt;&lt; 3
</code></pre>
<p>Ugly, I know.</p>
]]></description>
    </item>
    <item>
      <title>Ubuntu 11.10 - Replace the Default (and Annoying) Orange Scheme</title>
      <link>https://blog.angeloff.name/post/2011/10/14/ubuntu-11-10-replace-the-default-and-annoying-orange-scheme/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2011/10/14/ubuntu-11-10-replace-the-default-and-annoying-orange-scheme/</guid>
      <pubDate>Fri, 14 Oct 2011 13:03:00 GMT</pubDate>
      <description><![CDATA[<p>Switching to Ubuntu 11.10 is painful, ugly and time consuming... but more on that some other time.</p>
<p>I was quite surprised to see most of the theme control options are now gone. The Appearance panel has no colour tweaks and I hate the default orange scheme. Luckily, there is a way to change it in Gtk3:</p>
<pre><code class="language-shellsession">$ sudo apt-get install dconf-tools
$ dconf-editor
</code></pre>
<p>Browse to <code>org.gnome.desktop.interface</code>. Locate <code>gtk-color-scheme</code>. Edit the property:</p>
<pre><code class="language-css">bg_color: #f0f1f2;
selected_bg_color: #4677f0;
</code></pre>
<p>Change the colours to your liking. You may need to re-launch some apps for changes to take effect.</p>
<p>...now if I could only get those Gnome Terminal tabs to look darker.</p>
]]></description>
    </item>
    <item>
      <title>Compass Magick Tutorial - Part 2</title>
      <link>https://blog.angeloff.name/post/2011/04/29/compass-magick-tutorial-part-2/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2011/04/29/compass-magick-tutorial-part-2/</guid>
      <pubDate>Fri, 29 Apr 2011 16:41:00 GMT</pubDate>
      <description><![CDATA[<p>There is more to Compass Magick than gradients and borders. In the second part of the tutorial series, we will go through the steps to create a simple 3-state button with an icon.</p>
<!-- more -->

<h2>Recap of <a href="/post/2011/04/16/compass-magick-tutorial-part-1/">Part 1</a></h2>
<p>In Part 1 we completed the tutorial with a simple button-like shape:</p>
<p><img src="/assets/images/imgur/hBLg0.png" alt="Example 4"></p>
<p>We generated the shape using linear gradients, corners and borders from Magick:</p>
<pre><code class="language-sass">// intro.scss
$theme1: red;
$theme2: maroon;

$button_width:  320px;
$button_height: 24px;

body {
  background: transparent magick-canvas($button_width, $button_height,
    magick-fill(
      magick-linear-gradient(
        $theme1,
        $theme2
      )
    )
    magick-corners(10px)
    magick-border($theme2, 10px, 1px)
  );
}
</code></pre>
<p>To ensure we can easily change the theme colours, we introduced two <code>$theme</code> variables at the top of the file.</p>
<h2>Adding an Icon to the Button</h2>
<p>Pick an <a href="http://www.iconfinder.com/icondetails/27854/24/about_information_icon">image</a> and save it in your <code>images_dir</code> as <code>icon.png</code>. If you skipped Part 1 of this tutorial, make sure you have a directory named <code>images</code> in your project&#39;s root and add the following line to your Compass configuration:</p>
<pre><code class="language-ruby"># Add to config.rb
images_dir = &#39;images&#39;
</code></pre>
<p>Magick comes with a very handy <code>magick-compose</code> function which allows us to put one canvas on top of another. We cannot pass the image file directly to <code>magick-compose</code> as it will refuse anything other than a canvas object:</p>
<pre><code class="language-sass">// This will NOT work
magick-compose(&#39;icon.png&#39;)
</code></pre>
<p>You&#39;ve seen how to create a blank canvas using the <code>magick-canvas</code> function. We can also initialise a canvas object in several other ways, one of which includes the option to load a file from disk:</p>
<pre><code class="language-sass">// Loads icon.png and returns a Base64 encoded Data URL
magick-canvas(&#39;icon.png&#39;)
</code></pre>
<p>Let&#39;s put the two together for a working solution:</p>
<pre><code class="language-sass">// Loads icon.png and uses it as an overlay
magick-compose(magick-canvas(&#39;icon.png&#39;))
</code></pre>
<p>Adding the above line to our button code:</p>
<pre><code class="language-sass">// {intro =&gt; button}.scss
/* …snip… */

body {
  background: transparent magick-sprite(&#39;button&#39;, magick-canvas($button_width, $button_height,
    /* …snip… */
    magick-compose(magick-canvas(&#39;icon.png&#39;))
  ));
}
</code></pre>
<p>Yields the following result:</p>
<p><img src="/assets/images/imgur/LxR7H.png" alt="Example 5"></p>
<p>It&#39;s not exactly what I would call pretty so let&#39;s make some changes to the dimensions and colours of the button:</p>
<pre><code class="language-sass">// button.scss
$theme1: #3060bf;
$theme2: #5ca1e5;

$button_width:  280px;
$button_height: 32px;

/* …snip… */
</code></pre>
<p><img src="/assets/images/imgur/QrO1E.png" alt="Example 6"></p>
<p>The CSS <code>background-position</code> property allows control over where a background image appears inside its container. <code>magick-compose</code> gives us similar control. To offset the icon 5px horizontally and center it vertically, we pass <code>5px, 50%</code> after the canvas object (note arguments are comma-separated):</p>
<pre><code class="language-sass">// button.scss
/* …snip… */

body {
  background: transparent magick-sprite(&#39;button&#39;, magick-canvas($button_width, $button_height,
    /* …snip… */
    magick-compose(magick-canvas(&#39;icon.png&#39;), 5px, 50%)
  ));
}
</code></pre>
<p><img src="/assets/images/imgur/1dGXv.png" alt="Example 7"></p>
<h2>Applying Effects</h2>
<p>Magick packs several pixel-based effects - fade, brightness, contrast, saturation, vibrance and greyscale. We apply them to a canvas object just like we would apply borders or corners:</p>
<pre><code class="language-sass">magick-effect(fade, 50%)
</code></pre>
<p>The first argument selects the desired effect and the second one adjusts its strength.</p>
<p>For this tutorial, let&#39;s tune down the icon by making it semi-transparent and reducing the colour intensity:</p>
<pre><code class="language-sass">/* …snip… */
magick-compose(
  magick-canvas(&#39;icon.png&#39;,
    magick-effect(fade,      50%)
    magick-effect(greyscale, 50%)
  ),
  5px, 50%
)
/* …snip… */
</code></pre>
<p><img src="/assets/images/imgur/yvRaX.png" alt="Example 8"></p>
<p>The effects are applied to the canvas we are composing on top of the button shape. If we move <code>magick-effect</code> to the top-level canvas (where borders and corners are applied) then the entire button will be semi-transparent - not what we are after.</p>
<h2>Sprites, the Compass Way</h2>
<p>We are building a 3-state button. So far we have only constructed the code for our normal state. For the hover state, we simply remove the effects applied on the icon earlier. For the active state, we invert the gradient so the button appears pressed.</p>
<p>We could save the three states as three different images, but this is not good practise and it will result in three requests to the server.<br>The latest release of Compass offers an easy-to-use <a href="http://compass-style.org/help/tutorials/spriting/">spriting support</a>. You import the different button states and Compass takes care of the rest.</p>
<p>Let&#39;s start by moving our button code from the <code>body</code> CSS selector to a <code>$button_sprites</code> Sass variable.</p>
<pre><code class="language-sass">// button.scss
$theme1: #5ca1e5;
$theme2: #3060bf;

$button_width:  280px;
$button_height: 32px;

$button_sprites: magick-sprite(&#39;button&#39;, magick-canvas($button_width, $button_height,
  magick-fill(
    magick-linear-gradient(
      $theme1,
      $theme2
    )
  )
  magick-corners(10px)
  magick-border($theme2, 10px, 1px)
  magick-compose(
    magick-canvas(&#39;icon.png&#39;,
      magick-effect(fade,      50%)
      magick-effect(greyscale, 50%)
    ),
    5px, 50%
  )
));

body { }
</code></pre>
<p>If we look at the generated CSS, it should be an empty file since there isn&#39;t any code in the <code>body</code>. However, <code>button.png</code> is still generated in <code>images_dir</code> which is what we are after.</p>
<p>Before we proceed to out hover state, let&#39;s rename the generated sprite from <code>&#39;button&#39;</code> to <code>&#39;button/normal&#39;</code> which will generate a file <code>button/normal.png</code>. This naming convention is compatible with Compass spriting.</p>
<p>For our hover state, we copy the code for the normal state and remove the effects on the button icon. Append the code to <code>$button_sprites</code>:</p>
<pre><code class="language-sass">// button.scss
/* …snip… */

$button_sprites: magick-sprite(&#39;button/normal&#39;, magick-canvas($button_width, $button_height,
  /* …snip… */
)) magick-sprite(&#39;button/hover&#39;, magick-canvas($button_width, $button_height,
  magick-fill(
    magick-linear-gradient(
      $theme1,
      $theme2
    )
  )
  magick-corners(10px)
  magick-border($theme2, 10px, 1px)
  magick-compose(magick-canvas(&#39;icon.png&#39;), 5px, 50%)
));

body { }
</code></pre>
<p>We end up with two files: <code>button/normal.png</code> and <code>button/hover.png</code>.</p>
<p>Finally, copy the code for the hover state and play with the gradient stops to achieve a pressed button look. Append the code to <code>$button_sprites</code> again:</p>
<pre><code class="language-sass">// button.scss
/* …snip… */

$button_sprites: magick-sprite(&#39;button/normal&#39;, magick-canvas($button_width, $button_height,
  /* …snip… */
)) magick-sprite(&#39;button/hover&#39;, magick-canvas($button_width, $button_height,
  /* …snip… */
)) magick-sprite(&#39;button/active&#39;, magick-canvas($button_width, $button_height,
  magick-fill(
    magick-linear-gradient(
      darken($theme2, 10%),
      mix($theme1, $theme2)
    )
  )
  magick-corners(10px)
  magick-border($theme2, 10px, 1px)
  magick-compose(magick-canvas(&#39;icon.png&#39;), 5px, 50%)
));

body { }
</code></pre>
<p>We are now ready to create a single image for our 3-state button. It is as easy as adding an <code>import</code> line above the <code>body</code>:</p>
<pre><code class="language-sass">// button.scss
/* …snip… */

@import &#39;button/*.png&#39;;

body { }
</code></pre>
<p><img src="/assets/images/imgur/jg8Ao.png" alt="Example 9"></p>
<h2>Using the Button Sprite</h2>
<p>The final step is to turn an <code>&lt;a&gt;</code> element into a button:</p>
<pre><code class="language-sass">a {
  display: block;
  width: $button_width;
  height: $button_height;
  line-height: $button_height;
  text-align: center;
  text-decoration: none;
  color: #fff;

  @include button-sprite(normal);

  &amp;:hover  { @include button-sprite(hover); }
  &amp;:active { @include button-sprite(active); }
}
</code></pre>
<p>The <code>button-sprite</code> mixins are generated by Compass and allow us to easily switch the <code>background-position</code> property to select the desired button state. The result is:</p>
<iframe style="width: 100%; height: 200px" src="http://jsfiddle.net/aFNFu/embedded/result/"></iframe>

<h2>Conclusion</h2>
<p>There are many more features available in Magick. Check out the <a href="https://github.com/StanAngeloff/compass-magick/blob/master/APIs.md">list of all available commands</a> for a comprehensive reference.</p>
<p>Leave a comment if you have any questions or suggestions and visit the <a href="https://github.com/StanAngeloff/compass-magick">official Github</a> page of the project for up-to-date information and links to other resources.</p>
]]></description>
    </item>
    <item>
      <title>Compass Magick Tutorial - Part 1</title>
      <link>https://blog.angeloff.name/post/2011/04/16/compass-magick-tutorial-part-1/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2011/04/16/compass-magick-tutorial-part-1/</guid>
      <pubDate>Sat, 16 Apr 2011 17:47:00 GMT</pubDate>
      <description><![CDATA[<h2>Introduction</h2>
<p>We have all been there - you release a cool new website with all the goodies of CSS3 just to find several weeks later your Customer wants you to support Internet Explorer as well. It seems solid backgrounds don&#39;t cut it.</p>
<p>There are also cases where CSS3 isn&#39;t the right solution, whether you have custom shapes or other elements of your design you end up creating images for (SVG is a good solution for these cases, but there&#39;s that big 10-year old elephant sitting in the middle of the room again).</p>
<p>Compass Magick tries to solve these issues by allowing you to dynamically generate images from your Compass projects taking full advantage of variables, mixins, etc.</p>
<!-- more -->

<h2>History</h2>
<p>The initial version of the project relied on RMagick for all image manipulation. There were many quirks: gradients were not working properly, per-pixel manipulation was difficult and much more.
While I haven&#39;t worked with Ruby myself before, it also became apparent after some time RMagick was a big no-no in Ruby&#39;s land. The project is not actively maintained (last commit at the time of writing this post was on October 25, 2010) and compiling it is a big pain (especially on Windows/Cygwin).</p>
<p>Searching for an alternative solution, I stumbled upon <a href="http://www.aaronrussell.co.uk/blog/cross-browser-rgba-support/">compass-rgba</a>, a simple plugin for generating 1x1 images and saving them as PNG files, the goal being to support IE7 with its missing implementation for <code>rgba</code>.
The plugin is using <a href="https://github.com/wvanbergen/chunky_png">ChunkyPNG</a>, a pure Ruby library for reading and writing PNG images. Upon further investigation, I found it has very good support for per-pixel access and was a breeze to install. The author, Willem van Bergen, is also actively maintaining it, constantly adding new features and releasing new versions.</p>
<h2>Installation</h2>
<p>Moving away from the brief history lesson, installing Compass Magick is simple via RubyGems. <a href="http://beta.compass-style.org">Compass</a> ~&gt; 0.11.beta.5 and <a href="https://github.com/wvanbergen/chunky_png">ChunkyPNG</a> ~&gt; 1.1.0 are required.</p>
<pre><code>gem install compass-magick
</code></pre>
<p>You can optionally install OilyPNG ~&gt; 1.0.0 to speed up ChunkyPNG. Oily is a native mixin:</p>
<pre><code>gem install oily_png
</code></pre>
<p>If you have an existing project, you can start using Compass Magick by requiring the plugin from your Compass configuration:</p>
<pre><code class="language-ruby"># Add as the the first line in your config.rb
require &#39;magick&#39;
</code></pre>
<p>If you are starting a new Compass project, to include Magick add <code>-r magick</code> to the command line:</p>
<pre><code>compass create -r magick my_project
</code></pre>
<h2>A Surface</h2>
<p>Everything starts with a canvas:</p>
<pre><code class="language-sass">magick-canvas(320px, 200px)
</code></pre>
<p>The code above creates a new Magick canvas and initialises its width and height. The canvas is fully transparent. This line by itself doesn&#39;t do much, so let&#39;s add it as a page background:</p>
<pre><code class="language-sass">// intro.scss
body {
  background: transparent magick-canvas(320px, 200px);
}
</code></pre>
<p>Once you compile the source <code>intro.scss</code>, have a look at the produced <code>.css</code> - you should see a Base64 encoded Data URL of what is essentially a 320x200 transparent PNG serialised:</p>
<pre><code class="language-sass">body {
  background: transparent url(&#39;data:image/png;base64,…&#39;);
}
</code></pre>
<h2>Commands</h2>
<p>You can perform drawing operations on a Magick canvas just like any other canvas. Commands are executed in the order they are specified in the source file. There are commands for drawing borders, generating gradients and much more. To keep things simple, let&#39;s turn our transparent canvas yellow:</p>
<pre><code class="language-sass">// intro.scss
body {
  background: transparent magick-canvas(320px, 200px,
    magick-fill(yellow)
  );
}
</code></pre>
<p><img src="/assets/images/imgur/j1KUk.png" alt="Example 1"></p>
<p>…and just like that we turned our canvas yellow. <code>magick-fill</code> accepts semi-transparent colors and most importantly of all, variables:</p>
<pre><code class="language-sass">// intro.scss
$theme1: yellow;
$theme2: blue;

body {
  background: transparent magick-canvas(320px, 200px,
    magick-fill($theme1)
    magick-fill(rgba($theme2, 0.5))
  );
}
</code></pre>
<p><img src="/assets/images/imgur/3o3yy.png" alt="Example 2"></p>
<p>What happened there? We created a 320x200 canvas and executed two commands on it:</p>
<ol>
<li>Fill the entire canvas with <code>$theme1</code> (yellow)</li>
<li>Fill the entire canvas again with <code>$theme2</code> (blue), but at 50% opacity</li>
</ol>
<h2>Types</h2>
<p>Compass Magick has support for linear gradients. Gradients are not drawing functions, but fill types. You don&#39;t apply a gradient directly on the canvas, rather you use it as an argument to a drawing function, one like <code>magick-fill</code> for example. Let&#39;s create a very simple top-to-bottom gradient and apply it on our canvas from the previous examples:</p>
<pre><code class="language-sass">// intro.scss
$theme1: red;
$theme2: maroon;

body {
  background: transparent magick-canvas(320px, 200px,
    magick-fill(
      magick-linear-gradient(
        $theme1,
        $theme2
      )
    )
  );
}
</code></pre>
<p><img src="/assets/images/imgur/V9pb3.png" alt="Example 3"></p>
<h2>Going Further</h2>
<p>Compass Magick has a very powerful <a href="https://github.com/StanAngeloff/compass-magick/blob/master/APIs.md">set of functions</a>. Adding corners and a border is trivial and we can quickly turn our canvas into a button:</p>
<pre><code class="language-sass">// intro.scss
$theme1: red;
$theme2: maroon;

$button_width:  320px;
$button_height: 24px;

body {
  background: transparent magick-canvas($button_width, $button_height,
    magick-fill(
      magick-linear-gradient(
        $theme1,
        $theme2
      )
    )
    magick-corners(10px)
    magick-border($theme2, 10px, 1px)
  );
}
</code></pre>
<p><img src="/assets/images/imgur/hBLg0.png" alt="Example 4"></p>
<h2>Saving the Canvas</h2>
<p>Unfortunately Base64 encoded Data URLs are not supported by all browsers and versions. To save the button we generated on disk, we first need to alter our Compass configuration:</p>
<pre><code class="language-ruby"># Add to config.rb
images_dir = &#39;images&#39;
</code></pre>
<p>We can now wrap everything in <code>magick-sprite</code> to write the output on disk:</p>
<pre><code class="language-sass">// intro.scss
/* …snip… */

body {
  background: transparent magick-sprite(&#39;button&#39;, magick-canvas($button_width, $button_height,
    /* …snip… */
  ));
}
</code></pre>
<p>The result will be <code>button.png</code> in the configured <code>images_dir</code>. The file is optimised for best compression, but you could further post-process it with tools like <a href="http://optipng.sourceforge.net/">OptiPNG</a>.</p>
<h2>Conclusion</h2>
<p>This post is just an introduction to Compass Magick. There are many more features available, some of which include image composing, cropping, masking, drop shadows and pattern generation.
Check out the <a href="https://github.com/StanAngeloff/compass-magick/blob/master/APIs.md">list of all available commands</a> for a comprehensive reference.</p>
<p>I hope you found this short walk-through useful.
Leave a comment if you have any questions or suggestions and visit the <a href="https://github.com/StanAngeloff/compass-magick">official Github</a> page of the project for up-to-date information and links to other resources.</p>
<p><strong>UPDATE</strong>: <a href="/post/2011/04/29/compass-magick-tutorial-part-2/">Part 2 is now available</a></p>
]]></description>
    </item>
    <item>
      <title>Yoke - a drop-in, quick and dirty alternative to Sprockets</title>
      <link>https://blog.angeloff.name/post/2011/02/23/yoke-a-drop-in-quick-and-dirty-alternative-to-sprockets/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2011/02/23/yoke-a-drop-in-quick-and-dirty-alternative-to-sprockets/</guid>
      <pubDate>Wed, 23 Feb 2011 18:02:00 GMT</pubDate>
      <description><![CDATA[<p>In local development, I tend to create separate pieces of JavaScript for every controller, model, view, etc. I loved the idea of Sprockets -- grab all these files and stitch them together. While it worked well for a while (on the command-line), I got fed up with how slow it runs, especially on Ruby under Cygwin.<br>So, what to do? Node.js of course. Why? It&#39;s fast, it&#39;s super-easy to install and writing a script on top of it is a breeze. Meet Yoke:</p>
<pre><code class="language-javascript">#!/usr/bin/env node

var fs = require(&quot;fs&quot;),
  path = require(&quot;path&quot;),
  options = {
    verbose: false,
    directories: [&quot;.&quot;],
  };

var includeFollowing = false;
process.argv.slice(2).forEach(function (option) {
  if (option === &quot;-v&quot; || option === &quot;--verbose&quot;) {
    options.verbose = true;
  } else if (option === &quot;-I&quot; || option === &quot;--include&quot;) {
    includeFollowing = true;
  } else if (option.indexOf(&quot;-I&quot;) === 0) {
    options.directories.push(option.substring(2));
  } else if (includeFollowing) {
    options.directories.push(option);
    includeFollowing = false;
  }
});

function findOne(file, directories) {
  var resolved = null;
  directories.forEach(function (directory) {
    if (resolved) {
      return;
    }
    var target = path.join(directory, file.replace(/\.js$/, &quot;&quot;) + &quot;.js&quot;);
    if (fs.existsSync(target)) {
      resolved = target;
    }
  });
  return resolved;
}

function pad(level) {
  return Array(level * 2 + 1).join(&quot; &quot;);
}

function processOne(file, level) {
  var lines = fs.readFileSync(file, &quot;utf8&quot;);
  level || (level = 0);
  if (options.verbose) {
    console.error(pad(level) + &quot;&gt; &quot; + file + &quot;\n&quot;);
  }
  lines = lines.replace(
    /^\s*\/\/=\s*require\s+([&quot;&lt;])([^&quot;&gt;]+).$/gm,
    function (match, type, location) {
      var resolved = findOne(
        location,
        type === &quot;&lt;&quot; ? options.directories : [path.dirname(file)],
      );
      if (resolved) {
        return processOne(resolved, level + 1);
      }
      throw new Error(
        &quot;Cannot resolve require:\n\n    &quot; + match + &quot;\n\n in file &quot; + file,
      );
    },
  );
  return lines;
}

process.stdout.write(processOne(process.argv.pop()));
</code></pre>
<p>To use, copy the script above on <code>$PATH</code> and then:</p>
<pre><code>yoke [-I path[ -I path]...] input.js &gt; output.js
</code></pre>
<p>In most cases, you would just need to replace your existing <code>sprocketize</code> command with <code>yoke</code>. Both <code>&lt;file&gt;</code> and <code>&quot;file&quot;</code> requires are supported.</p>
]]></description>
    </item>
    <item>
      <title>A quick and dirty way to use namespaces in CoffeeScript</title>
      <link>https://blog.angeloff.name/post/2010/12/07/a-quick-and-dirty-way-to-use-namespaces-in-coffeescript/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/12/07/a-quick-and-dirty-way-to-use-namespaces-in-coffeescript/</guid>
      <pubDate>Tue, 07 Dec 2010 16:07:00 GMT</pubDate>
      <description><![CDATA[<pre><code class="language-coffeescript"># Code:
#
namespace = (target, name, block) -&gt;
  [target, name, block] = [exports ? window, arguments...] if arguments.length &lt; 3
  top    = target
  target = target[item] or= {} for item in name.split &#39;.&#39;
  block target, top

# Usage:
#
namespace &#39;Hello.World&#39;, (exports) -&gt;
  # `exports` is where you attach namespace members
  exports.hi = -&gt; console.log &#39;Hi World!&#39;

namespace &#39;Say.Hello&#39;, (exports, top) -&gt;
  # `top` is a reference to the main namespace
  exports.fn = -&gt; top.Hello.World.hi()

Say.Hello.fn()  # prints &#39;Hi World!&#39;
</code></pre>
<p>There you have it -- should work both in the browser and on the server.</p>
]]></description>
    </item>
    <item>
      <title>Extract changed files from Git and prepare a deployment (Bash script)</title>
      <link>https://blog.angeloff.name/post/2010/11/05/extract-changed-files-from-git-and-prepare-a-deployment/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/11/05/extract-changed-files-from-git-and-prepare-a-deployment/</guid>
      <pubDate>Fri, 05 Nov 2010 22:34:00 GMT</pubDate>
      <description><![CDATA[<p>So, you have moved over to Git. Well done! You have big plans for your future deployment process -- it is going to be automated and thoroughly tested... but you still have to support your existing legacy products. If you are like me, you most likely started with simple FTP copies (oh, this takes me back). I moved over from SVN and TortoiseSVN was my primary choice for a desktop client. After each deployment, I would create an SVN tag so next time I can get a list of all changed files. In TortoiseSVN it&#39;s as simple as selecting two revisions while holding down the Shift key and doing a <em>Compare Revisions</em>. From the new window you can export all changed files to a new location. If your project in 100MB in size, you only ever have to deal with modified files on subsequent updates. Simple (or so I thought back then).</p>
<p>Moving over to Git has thought me many things. I used to love <a href="/post/2010/08/24/alternative-cygwin-terminal-shell/">my Cygwin console</a> even before the switch and I&#39;ve learnt to do pretty much every daily task in it. But the one thing I really needed and didn&#39;t have with Git was an option to copy modified files from the working tree between two commits. It wasn&#39;t available on the command line, nor in any of the <a href="http://cola.tuxfamily.org/">clients</a> <a href="http://sourceforge.net/projects/gitextensions/">I&#39;ve tried</a> <a href="http://code.google.com/p/tortoisegit/">so far</a>. So having been playing with shell scripts for a few weeks, I decided to put one together which would do just that:</p>
<pre><code class="language-bash">#!/bin/bash

BOLD=&quot;\033[1m&quot;
_BOLD=&quot;\033[22m&quot;
RED=&quot;\033[31m&quot;
YELLOW=&quot;\033[33m&quot;
GREEN=&quot;\033[32m&quot;
RESET=&quot;\033[39m&quot;

range=$1
if [ -z &quot;$range&quot; ]; then
  echo -e &quot;${BOLD}${RED}You must specify a &#39;&lt;since&gt;..&lt;until&gt;&#39; argument.${RESET}${_BOLD}&quot;
  exit 1
fi

if [ -z &quot;$2&quot; ]; then
  target=&quot;$( pwd )/.deployments&quot;
else
  target=$( echo &quot;$2&quot; | sed -e &#39;s#/\+$##g&#39; )
fi

if [ -d &quot;$target&quot; ]; then
  echo -ne &quot;Do you wish to remove &#39;$target&#39; first? [Y/n] &quot;
  read prompt
  if [ -z &quot;$prompt&quot; ] || [ &quot;$prompt&quot; == &quot;Y&quot; ] || [ &quot;$prompt&quot; == &quot;y&quot; ]; then
    echo -e &quot;  ${YELLOW}Purging &#39;$target&#39;...${RESET}&quot;
    if [ -d &quot;$target&quot; ]; then
      rm -Rf &quot;$target&quot;
    fi
    echo -e &quot;  ${GREEN}Done.${RESET}&quot;
  fi
fi

mkdir -p &quot;$target&quot;

LOG=$( git whatchanged -m --oneline &quot;$range&quot; | awk &#39;{
  if ($1 ~ /^:/) {
    print $5 &quot;:&quot; $6
  }
}&#39; | tac )

length=$( echo &quot;$LOG&quot; | wc -l )
manual=&#39;&#39;

index=0
for command in $LOG; do
  operation=${command:0:1}
  filepath=${command:2}
  case $operation in
    &quot;A&quot; | &quot;M&quot;)
      if [ -f &quot;$filepath&quot; ]; then
        destination=$( dirname &quot;$target/$filepath&quot; )
        filename=$( basename &quot;$filepath&quot; )
        mkdir -p &quot;$destination&quot;
        cp -f &quot;$filepath&quot; &quot;$target/$filepath&quot;
      fi
    ;;
    &quot;D&quot;)
      manual=&quot;$manual\n$filepath&quot;
    ;;
    *)
    echo -e &quot;${BOLD}${RED}Unknown operation $operation on file $filepath.${RESET}${_BOLD}&quot;
    exit 4
    ;;
  esac
  let &quot;index++&quot;
  echo -ne &quot;\r${YELLOW}Processing ${length} files...${RESET} $( echo &quot;scale=2; ( $index / $length ) * 100.00&quot; | bc )%&quot;
done
echo

if [ ! -z &quot;$manual&quot; ]; then
  echo $( echo -e &quot;$manual&quot; | sed -e &#39;s/^\s\+//g&#39; | sort -u ) &gt; &quot;$target/.delete&quot;
  echo -e &quot;[WARN] Please manually delete the files listed in &#39;${BOLD}.delete${_BOLD}&#39;&quot;
fi

echo -e &quot;${GREEN}Done.${RESET}&quot;
</code></pre>
<p>Paste the above in a script on your <code>$PATH</code>. Using <code>gitk</code> or another tool find the first commit you want to include in your extract. Invoke the script as below:</p>
<pre><code class="language-shellsession">$ git-extract initial_hash_of_first_commit_to_include..HEAD
Do you wish to remove &#39;.deployments&#39; first? [Y/n]
  Purging &#39;.deployments&#39;...
  Done.
Processing 10 files... 100.00%
Done.
</code></pre>
<p>A new directory <code>.deployments</code> will be created with all files that have changed in the given commits range. If files were deleted, a <code>.delete</code> file will be generated and you have to handle these manually.</p>
<p>I haven&#39;t found a better solution yet, but I am sure there is a <em>Git way</em> to do just what I am after. This script is a hack to get the job done.</p>
<p>Leave a comment if you found this post useful. Fork <a href="https://gist.github.com/664680">the Gist</a> and modify it to suit your needs.</p>
]]></description>
    </item>
    <item>
      <title>Vim 7 on Red Hat Enterprise Linux (RHEL)</title>
      <link>https://blog.angeloff.name/post/2010/10/15/vim-7-on-red-hat-enterprise-linux-rhel/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/10/15/vim-7-on-red-hat-enterprise-linux-rhel/</guid>
      <pubDate>Fri, 15 Oct 2010 14:53:00 GMT</pubDate>
      <description><![CDATA[<p>Following my <a href="/post/2010/10/15/git-on-red-hat-enterprise-linux-rhel-4-i386/">last post</a> I moved on to installing Vim 7.x as the one that comes with RHEL 4 is pretty outdated (6.x).</p>
<h2>Vim 7.2 from SVN</h2>
<p>Tested on RHEL 4 i386:</p>
<pre><code class="language-shellsession">$ cd ~
$ svn co https://vim.svn.sourceforge.net/svnroot/vim/vim7
$ cd vim7
$ ./configure --prefix=/usr --with-features=huge --disable-gui --without-x --enable-rubyinterp --enable-cscope --enable-multibyte
$ make &amp;&amp; make install
$ vim --version
VIM - Vi IMproved 7.2 (2008 Aug 9)
</code></pre>
<h2>Vim 7.3 from Mercurial</h2>
<p>Tested on RHEL 5 x86_64:</p>
<pre><code class="language-shellsession">$ cd ~
$ yum install hg ncurses-devel
$ hg clone https://vim.googlecode.com/hg/ vim
$ cd vim
$ ./configure --prefix=/usr --with-features=huge --disable-gui --without-x --enable-rubyinterp --enable-cscope --enable-multibyte
$ make &amp;&amp; make install
$ vim --version
VIM - Vi IMproved 7.3 (2010 Aug 15)
</code></pre>
<p>RHEL 4 comes with <code>up2date</code>. I tried <code>-i mercurial</code> and <code>-i hg</code>, but both failed. Vim offers an archived download so you can skip steps 3-4 above and instead use:</p>
<pre><code class="language-shellsession"># [..]
$ wget ftp://ftp.vim.org/pub/vim/unix/vim-7.3.tar.bz2
$ tar xjvf vim-7.3.tar.bz2
$ cd vim73
# [..]
</code></pre>
<p>Let me know if this post helped you or if you had to install any additional libraries.</p>
]]></description>
    </item>
    <item>
      <title>Git on Red Hat Enterprise Linux (RHEL) 4 i386</title>
      <link>https://blog.angeloff.name/post/2010/10/15/git-on-red-hat-enterprise-linux-rhel-4-i386/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/10/15/git-on-red-hat-enterprise-linux-rhel-4-i386/</guid>
      <pubDate>Fri, 15 Oct 2010 14:04:00 GMT</pubDate>
      <description><![CDATA[<p>I have been struggling with this for a while now. There is no <code>yum</code> to begin with and <code>up2date</code> doesn&#39;t help much either (no <code>git-*</code> packages). Here is a quick solution:</p>
<pre><code class="language-shellsession">$ cd ~
$ wget http://packages.sw.be/git/git-1.7.3-1.el4.rf.i386.rpm
$ wget http://packages.sw.be/git/perl-Git-1.7.3-1.el4.rf.i386.rpm
$ rpm -ivh --nodeps git-1.7.3-1.el4.rf.i386.rpm perl-Git-1.7.3-1.el4.rf.i386.rpm
$ git --version
</code></pre>
<p>You can browse <a href="http://packages.sw.be/git/">packages.sw.be/git/</a> for the latest packages and update the above accordingly.</p>
]]></description>
    </item>
    <item>
      <title>MinTTY at your fingertips</title>
      <link>https://blog.angeloff.name/post/2010/09/11/mintty-at-your-fingertips/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/09/11/mintty-at-your-fingertips/</guid>
      <pubDate>Sat, 11 Sep 2010 23:38:00 GMT</pubDate>
      <description><![CDATA[<p>How often do you need to get in and out of your terminal as quickly as possible? I use <a href="http://www.cygwin.com">Cygwin</a> for Linux emulation under Windows and <a href="http://code.google.com/p/mintty/">MinTTY</a> as my terminal of choice. MinTTY is great as it supports semi-transparent backgrounds and fullscreen mode (and lots more, be sure to check out the homepage). It is so tiny I don&#39;t mind having a copy of it running at all times, however it bugs me when I see its icon on the taskbar. The following is an <a href="http://www.autohotkey.com/">AutoHotkey</a> script which launches a new MinTTY window, if one is not started already, sets it up in fullscreen mode and lets you do your work until you press <strong>Win+C</strong> again to send it to the background and remove all traces of it on your desktop.</p>
<pre><code class="language-autohotkey">; AutoHotkey script, download from:
;   http://www.autohotkey.com/
; NOTE: Save this file with Windows line endings i.e. \r\n
;

cmd_line  := &quot;C:\bin\cygwin\bin\mintty.exe /bin/zsh --login&quot;
wnd_class := &quot;ahk_class mintty&quot;

#c::

DetectHiddenWindows, on

Maximize()
{
	global
	WinShow
	WinActivate
	WinGetPos, X, Y, Width, Height
	SysGet, FullScreenWidth, 78
	SysGet, FullScreenHeight, 79
	If (X &lt;&gt; 0) or (Y &lt;&gt; 0) or (Width &lt;&gt; FullScreenWidth) or (Height &lt;&gt; FullScreenHeight)
	{
		Send !{Enter}
	}
}

If WinExist(wnd_class)
{
	IfWinActive
	{
		WinMinimize
		WinHide
	}
	Else
	{
		Maximize()
	}
}
Else
{
	Run % cmd_line, , Hide
	WinWait % wnd_class, , 5
	If ErrorLevel
	{
		MsgBox, WinWait timed out. Please try pressing Win+C again.
	}
	Else
	{
		Maximize()
	}
}
</code></pre>
<p>If you haven&#39;t used AutoHotkey before make sure you download a copy. You most definitely will find some use for it.</p>
<p>As for the script, it is possible to tweak it so the window is only taking half the screen and slides in from the top <em>(ah, Mac envy)</em>. I leave that for you to figure out.</p>
]]></description>
    </item>
    <item>
      <title>cd with bookmarks and auto-completion for Zsh</title>
      <link>https://blog.angeloff.name/post/2010/08/29/cd-with-bookmarks-and-auto-completion-for-zsh/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/29/cd-with-bookmarks-and-auto-completion-for-zsh/</guid>
      <pubDate>Sun, 29 Aug 2010 12:00:00 GMT</pubDate>
      <description><![CDATA[<p>If you are like me, you do a lot of terminal work and <code>cd</code> is your friend (or enemy). I was getting really tired to <code>cd /home/stan/projects/important-project/src/</code> every time I launch my shell. It&#39;s bad enough when you have one project to work on, but as things get scattered, you tend to do more directory traversing than actual coding.</p>
<p>Up until recently I was using <a href="http://code.google.com/p/go-tool/">go-tool</a>. From the website:</p>
<blockquote>
<p><code>go</code> is a small shell command for changing directories quickly. Typically you have a set of directories that you work in. Typing out the names of those dirs in full can be tedious. <code>go</code> allows you to give a shortcut name for a directory -- say <code>ko</code> for <code>D:\trentm\main\Apps\Komodo-devel</code> [..]</p>
</blockquote>
<p>It&#39;s a great tool, but it doesn&#39;t work with Zsh out-of-the box (trivial to modify the Bash example to fake it). It&#39;s also based on Python and can be very slow when using it in a fresh terminal window. I really needed a solution that was native and didn&#39;t require a lot of effort to set up.</p>
<h2>The &#39;Thin&#39; Option</h2>
<p>I stumbled upon <a href="http://ivan.fomentgroup.org/blog/2010/01/29/zsh-bookmarks-for-cd-change-directory-with-completion/">Ivan Čukić&#39;s excellent blog post</a>. It&#39;s so cool, I couldn&#39;t resist trying it. I took the functions and tweaked the path where the database is stored and how it is accessed. This is a better solution compared to <code>go</code> and as a bonus it also offers auto-completion:</p>
<pre><code class="language-bash">ZSH_BOOKMARKS=&quot;$HOME/.zsh/cdbookmarks&quot;

function cdb_edit() {
  $EDITOR &quot;$ZSH_BOOKMARKS&quot;
}

function cdb() {
  local index
  local entry
  index=0
  for entry in $(echo &quot;$1&quot; | tr &#39;/&#39; &#39;\n&#39;); do
    if [[ $index == &quot;0&quot; ]]; then
      local CD
      CD=$(egrep &quot;^$entry\\s&quot; &quot;$ZSH_BOOKMARKS&quot; | sed &quot;s#^$entry\\s\+##&quot;)
      if [ -z &quot;$CD&quot; ]; then
        echo &quot;$0: no such bookmark: $entry&quot;
        break
      else
        cd &quot;$CD&quot;
      fi
    else
      cd &quot;$entry&quot;
      if [ &quot;$?&quot; -ne &quot;0&quot; ]; then
        break
      fi
    fi
    let &quot;index++&quot;
  done
}

function _cdb() {
  reply=(`cat &quot;$ZSH_BOOKMARKS&quot; | sed -e &#39;s#^\(.*\)\s.*$#\1#g&#39;`)
}

compctl -K _cdb cdb
</code></pre>
<h3>How to Use It</h3>
<p>Paste the above code at the bottom of your <code>~/.zshrc</code> file. Restart your terminal and run <code>cdb_edit</code>. This should bring up an empty buffer in your <code>$EDITOR</code>. To define shortcuts, use <code>shortcut  absolute/path</code>. Here is an example file:</p>
<pre><code class="language-shellsession">$ cdb_edit

public    /cygdrive/d/Workspace/public/
projects  /cygdrive/d/Workspace/projects/
</code></pre>
<h3>Try it Out</h3>
<p>Using the database above as an example:</p>
<pre><code class="language-bash">~ $ cdb public
/cygdrive/d/Workspace/public/ $
</code></pre>
<h2>The &#39;Fat&#39; Option</h2>
<p>If you are looking for something more sophisticated which wouldn&#39;t involve maintaining a database using vim then you need <a href="http://github.com/flavio/jump">Jump, a bookmarking system for the bash and zsh shells</a>. It&#39;s a great tool and quite easy to install too:</p>
<pre><code class="language-shellsession">$ gem install jump
$ cp `gem contents jump | grep zsh` ~/.jump_shell_driver
</code></pre>
<p>and a line in your <code>~/.zshrc</code> to make the magic happen: <code>source ~/.jump_shell_driver</code>.</p>
<p>Further instructions (incl. Bash) and a tutorial is available on the project&#39;s <a href="http://github.com/flavio/jump">GitHub page</a>.</p>
]]></description>
    </item>
    <item>
      <title>Building and using node.js on Windows (32 and 64-bit) through Cygwin</title>
      <link>https://blog.angeloff.name/post/2010/08/25/building-and-using-node-js-on-windows-32-and-64-bit-through-cygwin/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/25/building-and-using-node-js-on-windows-32-and-64-bit-through-cygwin/</guid>
      <pubDate>Wed, 25 Aug 2010 22:44:00 GMT</pubDate>
      <description><![CDATA[<p>I have been going through the existing GitHub page for building <a href="http://nodejs.org">node.js</a> on <a href="http://www.cygwin.com">Cygwin</a>/Windows adding my own comments/steps and missing packages. I believe this is now a full set of instructions that should get you cracking pretty quickly from scratch.</p>
<blockquote>
<p><a href="http://github.com/ry/node/wiki/Building-node.js-on-Cygwin-(Windows)">Building and using node.js on Windows (32 and 64-bit) through Cygwin</a></p>
</blockquote>
]]></description>
    </item>
    <item>
      <title>Alternative Cygwin terminal &amp; shell</title>
      <link>https://blog.angeloff.name/post/2010/08/24/alternative-cygwin-terminal-shell/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/24/alternative-cygwin-terminal-shell/</guid>
      <pubDate>Tue, 24 Aug 2010 10:20:00 GMT</pubDate>
      <description><![CDATA[<p>I just realised many, if not most, Cygwin users stick with their default terminal which is the <em>Cygwin Bash Shell</em>. I never understood why this is the default with each installation. It is no better than <em>Command Prompt</em> -- horizontal window resizing is out of the question, custom fonts are limited and mouse support is, well... missing.</p>
<h2>Terminal</h2>
<p>If you have used PuTTY to connect to remote machines, you would love <a href="http://code.google.com/p/mintty/"><strong>MinTTY</strong></a>. It is based on code from PuTTY 0.60. Features as seen on the project&#39;s homepage include:</p>
<ul>
<li>Native Windows user interface that tries to keep things simple.</li>
<li>Support for UTF-8, CJK fonts, and Windows IMEs.</li>
<li>Drag &amp; drop and copy &amp; paste of text, files and folders. (Files and folders are inserted as quoted filenames.)</li>
<li>Extensive mouse support, e.g. mousewheel scrolling in less and opening files and URLs with Ctrl+click</li>
<li>Window transparency, including glass effect on Vista and 7.</li>
<li>Small program size and uick scrolling.</li>
</ul>
<p><img src="/assets/images/imgur/EBpvY.png" alt="MinTTY preview"></p>
<h2>Shell</h2>
<p>I encourage you to try <a href="http://www.zsh.org/"><strong>Zsh</strong></a> as an alternative to Bash (the default). Bash is fine, but if you are looking for better history management, lots of plug-ins and options for customisations you need to move on. Check out <a href="http://github.com/robbyrussell/oh-my-zsh">oh-my-zsh</a> for a collection of such add-ons.</p>
<p>You can install MinTTY and ZSH using Cygwin&#39;s <a href="http://www.cygwin.com/setup.exe">setup.exe</a>.</p>
<h3>MinTTY at your fingertips</h3>
<p>Having a terminal keystroke away is essential in my day-to-day work. I need to be able to quickly get in and out of it -- <a href="/post/2010/09/11/mintty-at-your-fingertips/">read how to do it</a>.</p>
]]></description>
    </item>
    <item>
      <title>node-paperserve - Quick and dirty web server from your working directory</title>
      <link>https://blog.angeloff.name/post/2010/08/17/node-paperserve-quick-and-dirty-web-server-from-your-working-directory/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/17/node-paperserve-quick-and-dirty-web-server-from-your-working-directory/</guid>
      <pubDate>Tue, 17 Aug 2010 14:57:00 GMT</pubDate>
      <description><![CDATA[<p><strong>Install</strong></p>
<pre><code class="language-shellsession">$ npm install paperserve
</code></pre>
<p><strong>Usage</strong></p>
<pre><code>paperserve [path-to-serve]

  -p, --port [PORT]  set the port to listen on, default 8000
  -q, --quiet        turn off any logging, default false
  -h, --help         display this help message
</code></pre>
<p>Here&#39;s what the output looks like:</p>
<pre><code>&gt;&gt;&gt; paperserve: running on port 8000, serving from &#39;/cygdrive/d/Workspace/public/node-paperserve&#39;
&gt;&gt;&gt; paperserve:   Press Ctrl-C to stop.
</code></pre>
<p>Source code can be found on <a href="http://github.com/StanAngeloff/node-paperserve">GitHub</a>. As for the motivation behind the project -- let&#39;s just say I prefer JavaScript to <a href="/post/2010/08/10/in-need-of-a-simple-web-server/">Python</a>.</p>
]]></description>
    </item>
    <item>
      <title>Cygwin, CoffeeScript &amp; Growl for Windows integration</title>
      <link>https://blog.angeloff.name/post/2010/08/16/cygwin-coffeescript-growl-for-windows-integration/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/16/cygwin-coffeescript-growl-for-windows-integration/</guid>
      <pubDate>Mon, 16 Aug 2010 17:24:00 GMT</pubDate>
      <description><![CDATA[<p>Let&#39;s start by adjusting where <a href="http://nodejs.org/">node.js</a> looks for libraries. We will need this later on when we use the newly implemented <a href="http://github.com/jashkenas/coffee-script/commit/b1b78dca47c83986c9654ec51fd9993f90a795e5"><code>-r</code></a> command-line switch in CoffeeScript. Open up your shell init file, in my instance <code>~/.zshrc</code>:</p>
<pre><code class="language-shellsession">$ vim ~/.zshrc
</code></pre>
<p>and add a line in there:</p>
<pre><code class="language-bash">export NODE_PATH=&quot;/cygdrive/d/Workspace/public/coffee-script/.coffee_libraries:$NODE_PATH&quot;
</code></pre>
<p>The path can be anywhere on your system so adjust it accordingly. Let&#39;s go ahead and create a file inside <code>.coffee_libraries</code>, name it <code>growlnotify-windows.coffee</code> and paste this code inside of it:</p>
<pre><code class="language-javascript">{ exec } = require &#39;child_process&#39;

icon = null
require(&#39;fs&#39;).realpath &quot;#{__dirname}/icon-coffee-cup.png&quot;, (exception, path) -&gt;
  exec &quot;cygpath -w &#39;#{path}&#39;&quot;, (exception, stdout) -&gt;
    icon = stdout
    process()

queue = []
process = -&gt;
  exec &quot;
  growlnotify
    &#39;/a:CoffeeScript&#39;
    &#39;/i:\&quot;#{ icon.replace(/&quot;/g, &#39;\\&quot;&#39;) }\&quot;&#39;
    &#39;/r:\&quot;success\&quot;,\&quot;exception\&quot;&#39;
    &#39;/n:\&quot;exception\&quot;&#39;
    &#39;/p:2&#39;
    &#39;/s:true&#39;
    \&quot;/t:\\\&quot;#{ exception.message.replace(/&quot;/g, &#39;\\&quot;&#39;) }\\\&quot;\&quot;
    \&quot;#{ exception.stack.replace(/&quot;/g, &#39;\\&quot;&#39;).replace(/\n/g, &#39;\\n&#39;) }\&quot;
  &quot; while exception = queue.shift()

CoffeeScript.on &#39;failure&#39;, (exception, task) -&gt;
  queue.push exception
  process() if icon
</code></pre>
<p>We also need a <a href="/assets/images/imgur/SaUrK.png">proper icon</a> -- save it in the script folder as <code>icon-coffee-cup.png</code>.</p>
<p>Next time you run the <code>coffee</code> command line utility, append <code>-r growlnotify-windows</code> like so:</p>
<pre><code class="language-shellsession">$ coffee -r growlnotify-windows -wc src/
</code></pre>
<p>and when the compiler encounters an exception, you will receive a nice UI prompt like this:</p>
<p><img src="/assets/images/imgur/M2OiE.png" alt="Smokestack theme preview"></p>
<p>Happy coding!</p>
]]></description>
    </item>
    <item>
      <title>Styling XUL applications like web pages</title>
      <link>https://blog.angeloff.name/post/2010/08/13/styling-xul-applications-like-web-pages/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/13/styling-xul-applications-like-web-pages/</guid>
      <pubDate>Fri, 13 Aug 2010 13:10:00 GMT</pubDate>
      <description><![CDATA[<p>If you don&#39;t know of XUL applications there are <a href="http://www.mozilla.org/projects/mozilla-based.html">many out there</a> in the wild. You are probably using a Mozilla XUL-based app without even realising it.</p>
<p>I am a <a href="http://www.activestate.com/komodo-edit">Komodo Edit</a> user myself and I love the platform. I have posted <a href="http://community.activestate.com/xpi/html-toolkit">several</a> <a href="http://community.activestate.com/xpi/aero-theme">extensions</a> if my words are not enough to prove it.</p>
<p>The greatest weakness of XUL apps in my book is how <strong>static</strong> they feel. They are not as dynamic and rich as HTML documents and as a result development is usually not as easy and elegant. You are forced to restart the application between updates or rely on hacky methods to reload it while running. Being frustrated with these facts, I decided to do something about it. It would be wonderful if you could just press <code>Ctrl+Alt+R</code> and have a fresh stylesheet loaded into your application -- much like existing solutions for <a href="https://chrome.google.com/extensions/detail/ojcnooebgeenefpfngjfifjcnhlkbbdd">Google Chrome</a> of <a href="https://addons.mozilla.org/en-US/firefox/addon/7465/">Firefox</a>. Here is one way you can do just this in Komodo:</p>
<pre><code class="language-javascript">(function () {
  for (
    var child, i = 0, length = document.childNodes.length;
    i &lt; length &amp;&amp; (child = document.childNodes[i]);
    i++
  ) {
    if (child.nodeType === 7) {
      if (child.nodeValue.indexOf(&quot;aero&quot;) &gt; 0) {
        /* UPDATE: &#39;aero&#39; with a keyword from your file name */
        child.nodeValue = &#39;discard=&quot;discard&quot;&#39;;
        document.removeChild(child);
      }
    }
  }

  var pi = document.createProcessingInstruction(
    &quot;xml-stylesheet&quot;,
    &#39;href=&quot;file:///D:/Workspace/public/komodo-aero-theme/src/skin/aero/theme.css?&#39; +
      new Date().getTime() +
      &#39;&quot; type=&quot;text/css&quot;&#39;,
  ); /* UPDATE: with path to a local resource; keep new Date()... */
  document.insertBefore(pi, document.firstChild);
})();
</code></pre>
<p>Create this as a macro and assign a key binding to it. Pressing it will discard any previously loaded stylesheet and inject a non-cached fresh copy of it right in the beginning of the document.</p>
<p>This can be simulated in any XUL app -- you would need a <code>keypress</code> handler and some code to deal with recognising the correct combination of keys and you are off on a good start.</p>
]]></description>
    </item>
    <item>
      <title>Get my Coffee, Compass and web server in the background, please</title>
      <link>https://blog.angeloff.name/post/2010/08/11/get-my-coffee-compass-and-web-server-in-the-background-please/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/11/get-my-coffee-compass-and-web-server-in-the-background-please/</guid>
      <pubDate>Wed, 11 Aug 2010 12:57:00 GMT</pubDate>
      <description><![CDATA[<p>This is a simple <strong>bash</strong> script I run from my project&#39;s working directory to get <a href="http://coffeescript.org">CoffeeScript</a>, <a href="http://compass-style.org/docs/reference/compass/">Compass</a> and a <a href="/post/2010/08/10/in-need-of-a-simple-web-server/">simple web server</a> running. Any changes to <code>*.(coffee|scss)</code> files will be compiled on the fly. Remember to check the console every now and then if you think you&#39;ve made an whoopsy:</p>
<pre><code class="language-bash">#!/bin/bash

stop()
{
  echo &quot;Shutting down...&quot;

  if [[ $SERVER_PID ]]; then kill -HUP $SERVER_PID; fi;
  if [[ $COMPASS_PID ]]; then kill -HUP $COMPASS_PID; fi;
  if [[ $COFFEE_PID ]]; then kill -HUP $COFFEE_PID; fi;

  if [ -f .coffee.pid ]; then rm -f .coffee.pid; fi;
  if [ -f .compass.pid ]; then rm -f .compass.pid; fi;
  if [ -f .server.pid ]; then rm -f .server.pid; fi;

  trap - INT

  echo &quot;Done.&quot;
  exit
}

if [ &quot;$1&quot; == &quot;start&quot; ]; then

  COFFEE_PID=0
  COMPASS_PID=0
  SERVER_PID=0

  trap stop INT

  echo &quot;Starting processes...&quot;

  coffee --watch --compile --output static/lib src &amp;
  COFFEE_PID=$!

  compass watch --config compass.config.rb --sass-dir src/styles --css-dir static/styles &amp;
  COMPASS_PID=$!

  python -m SimpleHTTPServer &amp;
  SERVER_PID=$!

  echo $COFFEE_PID &gt; .coffee.pid
  echo $COMPASS_PID &gt; .compass.pid
  echo $SERVER_PID &gt; .server.pid

  echo &quot;Use &#39;$0 stop&#39; to kill.&quot;

elif [ &quot;$1&quot; == &quot;stop&quot; ]; then

  if [ -f .coffee.pid ]; then read COFFEE_PID &lt; .coffee.pid; fi;
  if [ -f .compass.pid ]; then read COMPASS_PID &lt; .compass.pid; fi;
  if [ -f .server.pid ]; then read SERVER_PID &lt; .server.pid; fi;

  stop

else

  echo &quot;Usage: $0 [start,stop]&quot;

fi
</code></pre>
<p>You need an empty <code>compass.config.rb</code> file to be present. Mine usually has some goodness in it:</p>
<pre><code class="language-ruby">images_dir      = &#39;static/images&#39;
relative_assets = true
</code></pre>
]]></description>
    </item>
    <item>
      <title>In need of a simple web server</title>
      <link>https://blog.angeloff.name/post/2010/08/10/in-need-of-a-simple-web-server/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2010/08/10/in-need-of-a-simple-web-server/</guid>
      <pubDate>Tue, 10 Aug 2010 13:47:00 GMT</pubDate>
      <description><![CDATA[<p>I was hacking away on an AJAX application and needed to do some <code>XMLHttpRequest</code> goodness. Needless to say, working with the <code>file://</code> protocol has become very restrictive lately so I was in a need of a simple web server - this meant no configuration, no support, no hassle whatsoever:</p>
<pre><code class="language-shellsession">$ python -m SimpleHTTPServer &amp;
</code></pre>
<p>and your working directory is now accessible over at <code>http://localhost:8000/</code></p>
]]></description>
    </item>
    <item>
      <title>The difference between &quot;We don&apos;t offer this&quot; and &quot;We don&apos;t have it available, but...&quot;</title>
      <link>https://blog.angeloff.name/post/2009/06/19/the-difference-between-we-dont-offer-this-and-we-dont-have-it-available/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/06/19/the-difference-between-we-dont-offer-this-and-we-dont-have-it-available/</guid>
      <pubDate>Fri, 19 Jun 2009 23:40:00 GMT</pubDate>
      <description><![CDATA[<p>I picked up smoking recently after 4 years of active non-smoking. Reasons put aside, being back &#39;in the game&#39; I seem to have forgotten most of the brands I used to buy back in the days.</p>
<p>I went to a local store the week before, and asked for a brand that I probably made up since I couldn&#39;t remember the name. The cashier politely explained they <em>&quot;don&#39;t offer this&quot;</em> so I had to leave empty-handed. On my way to work I came by another store, and I decided to try my luck again, being the kind of persistent person I am. Tried my best to explain what I was looking for and this time I received a different reply -- <em>&quot;We don&#39;t have this brand available, but I think we have something you might like.&quot;</em> I am pretty sure the cashier did not have a clue what I was on about, but nevertheless she offered to help. I ended up recognising the brand I was after. Although it looks quite different from what it used to 4 years ago, I decided to buy a few packets.</p>
<p><strong>My point?</strong> Don&#39;t turn down Customers just because you don&#39;t understand their requirements. Always offer to help and be sure to mention any products which you might already have available. We, Customers (and that includes you), need to be educated and at times even pushed to the &#39;right&#39; direction. It&#39;s that simple.</p>
]]></description>
    </item>
    <item>
      <title>European Elections</title>
      <link>https://blog.angeloff.name/post/2009/05/16/european-elections/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/05/16/european-elections/</guid>
      <pubDate>Sat, 16 May 2009 12:33:00 GMT</pubDate>
      <description><![CDATA[<p><img src="http://4.bp.blogspot.com/_qu0PLx69f6Q/Sg6IhrjpOyI/AAAAAAAAAas/prWm1-nI0sg/s400/image_mychoice.jpg" alt=""></p>
<ul>
<li>Financial markets require control</li>
<li>Nuclear is core energy</li>
<li>Free trade, mobility and cultural exchange</li>
<li>Cars should run on electrical power</li>
<li>Education is an investment in the future</li>
<li>Optimised food is the future</li>
</ul>
<p>Head over to the <a href="http://www.myspace.com/europeanparliament">European Parliament @MySpace</a> for more information (if you have AdBlock Plus installed, you may need to disable it for that page only).</p>
]]></description>
    </item>
    <item>
      <title>Neurologist V.S. Ramachandran on your mind</title>
      <link>https://blog.angeloff.name/post/2009/02/16/neurologist-vs-ramachandran-on-your-mind/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/02/16/neurologist-vs-ramachandran-on-your-mind/</guid>
      <pubDate>Mon, 16 Feb 2009 23:39:00 GMT</pubDate>
      <description><![CDATA[<p>A fascinating talk about the human brain and how people who have sustained an injury help science put the bits of the puzzle together:</p>
<div align="center">
<iframe src="https://embed.ted.com/talks/vilayanur_ramachandran_on_your_mind" width="446" height="326" frameborder="0" scrolling="no" allowfullscreen></iframe>
</div>

<blockquote>
Three-pound mass of jelly [...] and it can contemplate itself contemplating the meaning of infinity.
<footer><cite>— Vilayanur Ramachandran</cite></footer>
</blockquote>
]]></description>
    </item>
    <item>
      <title>The &apos;Big Brother&apos; Advertising Framework</title>
      <link>https://blog.angeloff.name/post/2009/02/10/the-big-brother-advertising-framework/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/02/10/the-big-brother-advertising-framework/</guid>
      <pubDate>Tue, 10 Feb 2009 04:24:00 GMT</pubDate>
      <description><![CDATA[<p>Advertising still remains the number one income source for most websites. Whether you are a blogger who gets a handful of visitors or a company such as Facebook, it is likely you rely on adverts to generate a revenue. Nowadays you can start making money within minutes, all you need is a Google AdSense account and a couple of your best friends to get you started. Most solutions rely on content from your pages, but users visiting your website will not always be interested in what you have to say, and thus what the adverts have to offer.</p>
<p>Much like the popular TV show &#39;Big Brother&#39;, let&#39;s imagine an advertising system that knows a lot about you and what you like and are likely to buy in particular. To do so, the system relies on a centralised database that collects information from &#39;partners&#39;. Any website can opt in to participate and act as a &#39;partner&#39;. To start, you first identify your website with a set of keywords that best describe your business. Each time a user visits any of your pages, you forward information to the centralised database. This would usually contain the IP address of your visitor, keywords associated with the page and statistics, such as average time on the website, referrer and others. The advertising system aggregates all this information and builds a comprehensive profile of keywords based on you, the &#39;partner&#39;, and pages your user visits. As the user goes from website to website, the system knows more about them and things they search for, read and chat about.</p>
<p>At this point it might not seem as a big improvement. Most platforms already do most of the above today. Let&#39;s go a step further. Imagine a user browsing the web looking for pages with information on Halo 3 and XBox. We can safely assume the user is interested in purchasing an XBox console to play Halo 3, but we cannot tell for certain whether they already own one. Advertising &#39;partners&#39; can submit this kind of information back to the centralised database. If a &#39;partner&#39; is an on-line shop, upon each successful order a list of keywords that match the purchased products is submitted back to the database. At this point the advertising system can offer suggestions for Halo 3 expansion packs or XBox modifications, such as an HD player.</p>
<p>Using data-mining the aggregated information about a user can be sorted in a timeline which can later be analysed and used to provide up-to-date suggestions. If a user visits a page which contains the keywords <em>&#39;hd dvd&#39;</em>, but the user has been looking for <em>&#39;blue ray&#39;</em> in the last week, we can assume they are interested in an HD player of the latter kind and serve the appropriate advert.</p>
<p>With this kind of system privacy must be at the top of the list of concerns. Harmful websites may request adverts for a particular IP and based on the results, build a profile for a given user at their first visit. For this, and many other reasons, no personal information should even be kept on record. Details such as first name, surname, date of birth and others should always be rejected by the system. A community, much like the one driving Wikipedia, should keep an eye for harmful websites and abusers. Registrations should be allowed only by referral. Limits on the amount of adverts served per &#39;partner&#39; should be in place where appropriate.</p>
<p>More start-up companies are founded every day and they need a better source of income. Old companies are already making their best to optimise websites and make more sales, but there is only as much one can do. While contextual advertising might be hot today, I believe person-targeted advertising will soon replace it.</p>
<blockquote>
What really decides consumers to buy or not to buy is the content of your advertising, not its form.
<footer><cite>— David Ogilvy</cite></footer>
</blockquote>
]]></description>
    </item>
    <item>
      <title>The Social Mobile Device Concept</title>
      <link>https://blog.angeloff.name/post/2009/02/06/the-social-mobile-device-concept/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/02/06/the-social-mobile-device-concept/</guid>
      <pubDate>Fri, 06 Feb 2009 00:32:00 GMT</pubDate>
      <description><![CDATA[<p>If I am to ask you &#39;Which handset on the market has the best set of features&#39;, you would probably go for an iPhone, an <a href="http://code.google.com/android/">Android</a> phone, Windows Mobile or perhaps Palm&#39;s recently announced <a href="http://www.engadget.com/2009/01/08/palm-announces-web-os-platform/">WebOS</a> platform? Each of these has it&#39;s own unique set of features and flaws, but do they make a great social device? While you may be able to use your Google Calendar and Mail on most of them, you would still have to install applications for Twitter, Flickr, Facebook and anything else you are using on-line. It is cumbersome to deal with several background programs running at the same time. Your information is not organised into a single place, rather each service keeps its own copy which is disconnected from the rest…
Meet the social mobile device.</p>
<p><strong>The Contacts List</strong>: Your friends and family on Facebook are aggregated into groups. Names, addresses, telephone information, avatars are downloaded to your social device. No longer the need to keep an up-to-date information for everyone, updates on-line are propagated instantly.</p>
<p><strong>Messaging</strong>: Twitter is a great service and a lot of people are using it. I do tweet regularly, but on the other hand I don&#39;t recall the last time I sent someone a message through my phone. The social device replaces the SMS interface with Twitter. Your text messages become direct messages while you still keep the option to update your public timeline.</p>
<p><strong>Photos</strong>: Most handsets nowadays come with at least a 3 mega-pixels camera. Your social device will upload every photo to Flickr and auto-tag it with your current location. Friends and family can subscribe to your stream and will receive updates immediately. Photos can also be shared through Twitpic and replace today&#39;s MMS interface.</p>
<p><strong>Video</strong>: Recordings you make with the social device are uploaded to YouTube and where appropriate protected so only a handful of your Contacts can watch them.</p>
<p><strong>Mail and Calendar</strong>: Let&#39;s face it - in today&#39;s fast paced World you need to keep track of your schedule. Your social device will integrate seamlessly with Google. You can add personal events, send invitations and subscribe to public and friends&#39; calendars. Mail will be synchronised instantly so you can keep an eye on that very important Customer wherever you are.</p>
<p><strong>Documents</strong>: Text, spreadsheets and presentations live on Google Docs. Any changes you make on-line are reflected on the social device.</p>
<p><strong>Files</strong>: everything you collect or download on your social device is uploaded to the Cloud. Music, movies, programs they all live on-line while a local copy is kept where appropriate to improve performance. A BitTorrent client is provided for larger downloads.</p>
<p><strong>Multimedia</strong>: Streaming TV with a thousand of free channels is available through <a href="http://www.livestation.com/">Livestation</a> and radio through <a href="http://www.last.fm">Last.fm</a>.</p>
<p><strong>News</strong>: Newspapers are a thing of the past. The social device aggregates content from the hundreds of free sources available on-line. Breaking news, sports and the weather forecast can be accessed at any time. RSS is integrated with Google Reader and updated regularly.</p>
<p><strong>Extensions</strong>: What made Firefox a great browser are the free extensions available for download. You can customise almost every aspect of the interface and add new features. Extensions will also make a great add-on for your social device.</p>
<p><strong>Open</strong>: Built on top of open and dynamic technologies is a must-do.</p>
<p>These are just a handful of the services the social device might support. Seamless integration is provided throughout the interface. Think about using Mail to forward a presentation to your colleagues and watch their reactions.</p>
<p>The best part? Your contacts, messages, photos, video, mail, calendar, documents and files all live on-line. Even if you have to replace the device itself, you will not lose any data.</p>
<p>The social mobile device is just a concept, but it sure makes you think about how old and disconnect the technology we use today is. It&#39;s all about staying connected and sharing.</p>
<blockquote>
There is no delight in owning anything unshared.
<footer><cite>— Seneca (Roman philosopher, mid-1st century AD)</cite></footer>
</blockquote>
]]></description>
    </item>
    <item>
      <title>How much personal information do we share on-line?</title>
      <link>https://blog.angeloff.name/post/2009/02/04/how-much-personal-information-do-we-share-on-line/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/02/04/how-much-personal-information-do-we-share-on-line/</guid>
      <pubDate>Wed, 04 Feb 2009 04:33:00 GMT</pubDate>
      <description><![CDATA[<p><em>Disclaimer: I am a software engineer and as much am involved in many projects some of which may require the use of data mining. I am in no means a data mining expert.</em></p>
<p>We go on with our on-line identities without paying much attention to the details we share about our personal lives, interests, hobbies and friends. We have profiles on Facebook, accounts on Twitter, Flickr, YouTube, discussion boards and other public websites. These are all open and available to anyone. Could that affect us in any way?</p>
<p>Excuse me, did you just say data mining?</p>
<blockquote>
<p>Data mining is the process of sorting through large amounts of data and picking out relevant information. [...]
<a href="http://en.wikipedia.org/wiki/Data_mining">Wikipedia page on Data mining</a></p>
</blockquote>
<p>What good can it do? Imagine yourself sitting at home on a Saturday, no plans whatsoever, but things tend to get a bit boring. You go to <a href="http://www.i-have-no-plans-please-help.co.uk">www.i-have-no-plans-please-help.co.uk</a> and you enter your user name, the very same user name you share across most websites. Here is where the magic happens:</p>
<ul>
<li>You have a Facebook profile registered under that user name. Since your profile is not made public by default, another user can only see your friends and in some cases your and their status updates. Looking at the most popular groups and events, data can be extracted about your interests and causes you support.</li>
<li>You also happen to have a Twitter account where your timeline is visible to anyone. Your list of friends can be cross-referenced with the one downloaded from Facebook.</li>
<li>There is a page on Flickr where you share your favourite photos you&#39;ve taken whenever there was a cool party or a concert nearby. Groups can be cross-referenced with those available on Facebook.</li>
<li>In some cases you might be sharing your current location via services such as <a href="http://www.google.com/intl/latitude/intro.html">Google Latitude</a>.</li>
<li>YouTube introduced a new feature called Active Sharing not a long time ago. In a few words, it allows anyone to see videos you have watched. Groups, channels and friends are available and can be cross-referenced.</li>
<li>Let&#39;s not forget Google itself where you can run a query on your user name or your full name (available on any of the websites above) and get a somewhat accurate list of all other discussion boards and websites you actively participate in.</li>
</ul>
<p>Now imagine all that information gathered in just a few seconds. Using data mining relevant bits can be filtered and further analysed. Here is one possible suggestion <a href="http://www.i-have-no-plans-please-help.co.uk">www.i-have-no-plans-please-help.co.uk</a> might throw at you:</p>
<p><em>Hey, it turns out last Saturday you went to a fancy Chinese restaurant [via Twitter] and you enjoyed the food [via Flickr]. Your friends are currently not very far away [via Google Latitude] and are organising a party [via Facebook], but they don&#39;t have any good ideas for a nice place [via discussion boards]. You should take them to the Chinese restaurant and after that you might catch a movie. It seems like everyone is talking about <a href="http://www.imdb.com/title/tt1032755/">RocknRolla</a> [via Twitter, Facebook, IMDB boards]. And while you are at it, stop by Jennifer&#39;s place, her sister is in town [via Facebook] and you have a few hours to kill anyway.</em></p>
<p><em>* via xxx indicates the service(s) used to gather the information</em></p>
<p>It sounds a bit scary, doesn&#39;t it? But we are talking software here. The website doesn&#39;t really know you. It just analyses data and makes the best of it. What is scary is if someone decides to target you. We are bound to have someone take all this goodness and profit from it.</p>
<p>Don&#39;t get me wrong. I am not saying stop using Facebook, Twitter, Flickr and (your favourite services here). Rather, refrain from sharing too much about yourself and your friends.
I have to dash now, I&#39;ve just received an SMS recommendation for a new coffee shop I must try… wonder how they know I like coffee so much?</p>
<blockquote>
It's just as difficult to live in a self-made hell of privacy as it is to live in a self-made hell of publicity.
<footer><cite>— Michael Hutchence</cite></footer>
</blockquote>
]]></description>
    </item>
    <item>
      <title>Hello, I am a &apos;nightly freak&apos;. Pleased to meet you.</title>
      <link>https://blog.angeloff.name/post/2009/01/30/hello-i-am-a-nightly-freak-pleased-to-meet-you/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/01/30/hello-i-am-a-nightly-freak-pleased-to-meet-you/</guid>
      <pubDate>Fri, 30 Jan 2009 01:09:00 GMT</pubDate>
      <description><![CDATA[<p>You may never have heard the phrase <em>&#39;nightly freak&#39;</em> and there is probably a good reason for it i.e. it just came to me. As a typical Internet user, let&#39;s see what Google has to say on it:</p>
<blockquote>
<p>A nightly build [...] takes place automatically, typically when no one is likely to be working in the office. The results of the build are inspected by the arriving programmers, who generally place a priority on ensuring the [...] build does not break.
<a href="http://en.wikipedia.org/w/index.php?title=Nightlies&redirect=no">Wikipedia page on Nightlies</a></p>
</blockquote>
<p>While that may be a perfectly good definition, it still fails short to explain what I mean in details. Being a &#39;nightly freak&#39; for me means running the very latest and greatest version of a program. The reason they are called &#39;nightly builds&#39; /as suggested in the quote above/ usually has something to do with the fact they are produced at the end of the day, once everyone has left the office.</p>
<p><strong>What are the benefits</strong> you may ask? Nightlies:</p>
<ul>
<li>Usually contain fixes and features not present in the official version,</li>
<li>Are <em>experiments</em> in a way that they may offer a different approach to a task,</li>
<li>Can have much better performance,</li>
<li>Are a way for you, the User, to evaluate all of the above and submit feedback.</li>
</ul>
<p>Take, for example, Firefox. While you may be running version 3.0.x, I have already adopted 3.1 in my daily browsing. It contains a lot of new features among which <a href="http://en.wikipedia.org/wiki/Geolocation">Geolocation</a>, <a href="http://en.wikipedia.org/wiki/Private_browsing">Private Browsing a.k.a. porn mode</a> and a <a href="http://theora.org/faq/#10">free video codec</a>. Gmail, Facebook and other web applications perform in times faster than they do in 3.0.x.</p>
<p>Another great example is <a href="http://www.mozilla-europe.org/en/products/thunderbird/">Thunderbird</a> /if you have never heard of it before, think of what Firefox is to Internet Explorer and then apply the same concept to Outlook/. The nightly build contains so many new features it&#39;s hardly possible to fit them on a single blog post.</p>
<p>There is, however, a side effect to all the great new stuff you are getting. Bugs. Yes, nightlies are unstable, they crash a lot, they may even refuse to run or damage your computer /although I have never experienced the last/. Developers need to know about these issues and this is where we, the Users, come in. As a &#39;nightly freak&#39; I submit a lot of bug reports and sometimes even <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=466893">suggest a possible fix</a>. Your partipation ensures those bugs do not make it to the final version and also has the side effect of making you feel a tad better about yourself.</p>
<p>My advise to you is: get involved. Get the latest <a href="http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-trunk/">Firefox</a> or look for a nightly of your favourite program. Try it out, see if it crashes, inform the developers and enjoy a better product!</p>
<blockquote>
Observation is a passive science, experimentation an active science.
<footer><cite>— Claude Bernard</cite></footer>
</blockquote>
]]></description>
    </item>
    <item>
      <title>Perry Belcher on How To Double Your Productive Hours in Any Day</title>
      <link>https://blog.angeloff.name/post/2009/01/26/perry-belcher-on-how-to-double-your-productive-hours/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/01/26/perry-belcher-on-how-to-double-your-productive-hours/</guid>
      <pubDate>Mon, 26 Jan 2009 04:59:00 GMT</pubDate>
      <description><![CDATA[<iframe width="560" height="315" src="https://www.youtube.com/embed/rI8nJTlusQY" frameborder="0" allowfullscreen></iframe>

<p>I found this video while browsing on Twitter. It is more or less a follow up on my <a href="/2009/01/can-we-have-too-much-information.html">previous post on &#39;Can we have too much information?&#39;</a></p>
<p>I have been employing Perry&#39;s approach for a week. It really is comfortable knowing all you ever had to remember is now written down and away from everything else you need to deal with right now.</p>
<p>You can <a href="http://www.twitter.com/perrybelcher">follow Perry Belcher on Twitter</a> or have a look at <em>&quot;<a href="http://www.youtube.com/user/perrybelcher">some stupid home videos</a>&quot;</em>.</p>
]]></description>
    </item>
    <item>
      <title>Can we have too much information?</title>
      <link>https://blog.angeloff.name/post/2009/01/19/can-we-have-too-much-information/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/01/19/can-we-have-too-much-information/</guid>
      <pubDate>Mon, 19 Jan 2009 00:50:00 GMT</pubDate>
      <description><![CDATA[<p>The Internet is a great source of information, no one can deny it. While once you would have to go to the library or buy special literature to learn more about quantum physics, nowadays you can join one of the hundreds clubs available on the web or simply try Wikipedia <em>/Google is also entering the market with <a href="http://knol.google.com/">Knol</a>/</em>. There is nothing you can&#39;t learn about, all you need is time on your hands. You have the tools, you have the sources. But can we have too much information?</p>
<p>Did you know that every time you glance at the moon your brain throws something else away? We humans simply can&#39;t comprehend the vastness of information out there. Our brains have limited capacity, they can only store as much memories. When there is not enough room, something needs to go away. Stop and think about it for a second… yes, the simple act of observing an object costs you brain space. So does watching television or having a chat with your mates. Everything you do needs to be recorded so you can play it back later. But we are not like computers, we cannot &#39;add&#39; more space. What we have is what we get. What role does the Internet play in all this madness?</p>
<p>How many blogs do you follow on average? How many people do you have on Twitter? Do you find yourself spending countless hours browsing the web, going through websites? Researchers have found that ours brains are rewiring themselves to deal with how we manage the large amount of information available on the web. When you go to a website, it&#39;s rarely that you read through every single sentence as you would do with a book. Instead, you find your way around by skimming through information, lots and lots of information. Same applies for Twitter, if you are following many people on there, it&#39;s rarely that you read every single twit.</p>
<p>Let&#39;s connect the dots. One, we know ours brains have limited capacity. Two, we throw away old or unused memories to make room for current ones. Three, our brains work somewhat differently as we deal with huge amounts of data on a daily basis, but it&#39;s all in chunks. What do you get? One big mess.</p>
<p>Yes, we can have too much information and many people on the web do. We end up with brains filled with rubbish, things you won&#39;t probably ever use or need and yet we throw away childhood and school memories.</p>
<p>By now you are probably thinking does it all mean we should stop reading blogs and using Twitter or even go to such lengths as to say we should kill the Web? <strong>No.</strong> I think we should focus our attention on the information we are getting every single day. Why have 10, 000 people on Twitter when you are only interested in probably 1% of them, which is still a high number. Why read all those stupid blogs you&#39;ve meant to remove for ages and yet you spend hours every week to read the headings? Why bother to find what you need on that website when you could as easily try another Google query and get to what you want faster? Why watch television when you could find your way to news you are only interested in and have some real value in your work or daily life? I guess the list is endless, but the main point here is we should learn to filter the information we are allowing our brains to collect.</p>
<p>I, for one, intend to do all of the above and even go a step further. There is only as much data I can store in my brain, why not make the best of it?</p>
<blockquote>
There are billions of neurons in our brains, but what are neurons? Just cells. The brain has no knowledge until connections are made between neurons. All that we know, all that we are, comes from the way our neurons are connected.
<footer><cite>— Tim Berners-Lee, Weaving The Web (1999)</cite></footer>
</blockquote>
]]></description>
    </item>
    <item>
      <title>A new wave of applications hitting your desktop</title>
      <link>https://blog.angeloff.name/post/2009/01/16/a-new-wave-of-applications-hitting-your-desktop/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/01/16/a-new-wave-of-applications-hitting-your-desktop/</guid>
      <pubDate>Fri, 16 Jan 2009 02:22:00 GMT</pubDate>
      <description><![CDATA[<p>Back in the days when I started my first job as a software developer I was still playing with C, Pascal and other not-so-popular programming languages. Java was widespread and Microsoft was desperately trying to come out with a new platform to replace it. And so .NET was born and so my journey began.</p>
<p>I was given the task to complete several projects in ASP.NET. Those were the days of Web 1.0 and AJAX wasn&#39;t the buzz word it is today. As I learned more and more of how .NET works and what problems it solves, I became fascinated by anything Microsoft. Every project thrown at me was done with Microsoft&#39;s tools and technologies… but technologies change and that&#39;s the beauty of it.</p>
<p>Open-source projects were suddenly becoming more and more popular. Web applications were used more often than ever before. Once thought to be the land of wacky system administrators, open-source tools and software were making their way into the mainstream. I became ever more fascinated by the opportunities.</p>
<p>I started working on an open-source project called XOAD (formerly NAJAX). As the name suggests, it was a set of tools to allow you to do fancy things never seen before in web applications. As years went on, people realised the power of sharing, collaborating and pushing the limits of technologies. Somewhere around that time Web 2.0 was born.</p>
<p>We have all come to enjoy the wonders of web applications we use today. I don&#39;t have Microsoft Office installed any more. I do all my editing and spreadsheets in Google Docs. Why keep all my photos on my PC when I can as easily share them on Flickr? And so on, and so on.</p>
<p>You might wonder at this time - what new wave of applications? Where are you going with all this?</p>
<p>We love buzz words. We use them every day. How about &#39;cloud&#39; computing… or let&#39;s just call it &#39;The Cloud&#39;. Yes, that&#39;s the new buzz word everyone is looking up on Google. But what is it in reality? The simplest way to define it is to be really general and summarise it in a few words: Simply having your stuff on-line. Photos on Flickr; documents, bookmarks and contacts on Google; your favourite recipes stored on-line. And so on, and so on.</p>
<p><strong>Where are things heading?</strong>
We now have the tools to move many of our activities to the cloud. But we still run those dreadful desktop applications that take a lot of resources, time to install and support. What if there was a way to move those applications to the cloud as well, wouldn&#39;t that be nice for a change? It seems as Microsoft is finally pulling their act together and have come with a few ideas about the future of desktop applications. Welcome to your Live Mesh.</p>
<p>Mesh is a new service allowing you put up to 5GB of data on-line, free of charge. You even have a Live Desktop where you can download and preview those files. Need those reports you did last night, but have no access to your PC? No worries, get them from your Mesh. But the list of features doesn&#39;t end here. Mesh allows you to run applications as you would do on your desktop. That&#39;s right - the same application you would run on your PC now you run it anywhere you are and that&#39;s without having to wait for Setup to finish the install.</p>
<p>Let&#39;s let our imaginations run for a while: You go out with friends to enjoy a quiet evening at a local restaurant. You snap photos of everyone around the table and those are instantly uploaded to your Mesh and synced with all your friend&#39;s devices so everyone gets their own fair share of laugh. You get home and you open up your Messenger from within your Mesh. You didn&#39;t bother to install it and it&#39;s always with you no matter where you go. You chat for a while with your friends, exchange that very important website everyone&#39;s talking about. On the following day you are at the library and all your stuff is at your fingertip - friends, photos and that very dirty website.</p>
<p>It all sounds really good, doesn&#39;t it? I am somewhat glad to see Microsoft using open standards and pushing the boundaries of what today&#39;s technology can do to deliver a great end-user experience. I hope they won&#39;t screw up as they have done countless times in the past. Live Mesh is certainly a great hub to start your digital life.</p>
<p>I encourage you to give it a try at <a href="http://www.mesh.com">www.mesh.com</a> and share your thoughts. For those of you more interested in the underlying technology, have a look at <a href="http://channel9.msdn.com/posts/mtaulty/Live-Framework-MEWA-Hello-World/">Channel9</a> for a great video of a new-wave application.</p>
<blockquote>
The number one benefit of information technology is that it empowers people to do what they want to do. It lets people be creative. It lets people be productive. It lets people learn things they didn't think they could learn before, and so in a sense it is all about potential.
<footer><cite>— Steve Ballmer</cite></footer>
</blockquote>
]]></description>
    </item>
    <item>
      <title>How does Twitter affect your life?</title>
      <link>https://blog.angeloff.name/post/2009/01/15/how-does-twitter-affect-your-life/</link>
      <guid isPermaLink="true">https://blog.angeloff.name/post/2009/01/15/how-does-twitter-affect-your-life/</guid>
      <pubDate>Thu, 15 Jan 2009 02:45:00 GMT</pubDate>
      <description><![CDATA[<p>Up until recently I wasn&#39;t a big fan of Twitter. Who am I kidding - I used to make jokes of people using it. For bad or worse I am now hooked on it. A day does not go by without me having a sneak peak at my inbox to check what people have to say. How does it all affect me?</p>
<p>I used to watch a lot of TV shows and I mean a lot. The list is endless: CSI, Criminal Minds, Bones, Psych and shows you&#39;ve never heard of. I have thrown away those mindless action series and have started watching Qi, How It&#39;s Made, History Channel [...] instead. This <em>/what it might seem a small/</em> change had a bigger impact on me than I expected. I started looking for new and interesting stories; well-known facts and others not so wide-spread, but nevertheless, fascinating. Once I adopted Twitter it became another medium I use to gather bits and pieces of information. I also find myself looking up odd questions like &#39;What was the duration of a work week back in 1850?&#39; or &#39;How many Americans suffer from insomnia?&#39; Having the answer to a question, I rush to share it with others. What it will result in I can never tell. It might spark a discussion, it might throw someone off balance, it might even put a smile on one&#39;s face. I hope in many cases it is the latter.</p>
<p>How does Twitter affect you? Did it change anything in your day-to-day life?</p>
<p>Thank you for reading.</p>
<blockquote>
A sense of curiosity is nature's original school of education.
<footer><cite>— Smiley Blanton</cite></footer>
</blockquote>
]]></description>
    </item>
  </channel>
</rss>