http://nongraphical.com/2013-12-17T17:59:58-08:00How to match protobuf enum constants with values in Python2013-12-17T00:00:00-08:00http://nongraphical.com/2013/12/how-to-match-protobuf-enum-constants-with-values-in-python<p>It is sometimes very useful to be able to enumerate, in Python, all the values of an <code>enum</code> defined in a protobuf schema. For example, your code might receive a number representing an enum value, and you want to print a human-readable representation of it. While Google's official documentation states that "No type corresponding to <em>EnumName</em> is defined" in the generated code <sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>, we can still achieve this functionality by way of undocumented implementation details. Normally, it's a good idea to <em>not</em> rely on implementation details in your code, since they could be changed from underneath you, so this technique is probably best left to quick testing scripts. (I did in fact use this technique in a testing script, which inspired this article.)</p>
<p>Let's say you have an enum defined as follows:</p>
<pre><code>enum MyEnumType {
ENUM_VALUE_A = 100;
ENUM_VALUE_B = 120;
ENUM_VALUE_C = 140;
}
</code></pre>
<p>And you want a function that does a "reverse lookup" from the enum value to the enum name, like so:</p>
<pre><code>def enum_value_to_name(val):
# ...
enum_value_to_name(140) -> "ENUM_VALUE_C"
enum_value_to_name(100) -> "ENUM_VALUE_A"
enum_value_to_name(120) -> "ENUM_VALUE_B"
</code></pre>
<p>Here I'll present a simple implementation of <code>enum_value_to_name</code>, and afterwards how I arrived at this implementation:</p>
<pre><code>def enum_value_to_name(val):
desc = MyEnumType.DESCRIPTOR
for (k,v) in desc.values_by_name.items():
if v.number == val:
return k
return None # if val isn't a value in MyEnumType
</code></pre>
<p>This naive implementation is pretty easy to come by if you use do a little Python sleuthing. Compile the <code>.proto</code> file and import that module in a Python shell, for example:</p>
<pre><code>$ python
>>> import myproto_pb2 as pb2
>>> pb2.MyEnumType
<google.protobuf.internal.enum_type_wrapper.EnumTypeWrapper object at 0x10cfb6d10>
(as we can see, a type *does* get defined for MyEnumType,
but it's an internal implementation detail)
>>> pb2.MyEnumType.__dict__
{'DESCRIPTOR': <google.protobuf.descriptor.EnumDescriptor object at 0x10cfb6cd0>, '_enum_type': <google.protobuf.descriptor.EnumDescriptor object at 0x10cfb6cd0>}
(__dict__ is a dictionary representation of all the
attributes that an object has. It's an easy way to
inspect the internals of an object. 'DESCRIPTOR'
looks interesting, let's see what is in there)
>>> pb2.MyEnumType.DESCRIPTOR.__dict__
{'_serialized_end': 48, '_options_class_name': 'EnumOptions', 'name': 'MyEnumType', '_options': None, 'full_name': 'MyEnumType', 'containing_type': None, 'values': [<google.protobuf.descriptor.EnumValueDescriptor object at 0x10cfb6c50>], 'values_by_name': {'ENUM_VALUE_A': <google.protobuf.descriptor.EnumValueDescriptor object at 0x10cfb6c50>}, 'file': <google.protobuf.descriptor.FileDescriptor object at 0x10cfb6c10>, 'has_options': False, '_serialized_start': 18, 'values_by_number': {100: <google.protobuf.descriptor.EnumValueDescriptor object at 0x10cfb6c50>}}
(ooh, 'values_by_name' looks like what we want. Now
all we need to do is to extract a number (integer)
from those EnumValueDescriptor objects)
>>> desc = pb2.MyEnumType.DESCRIPTOR
>>> desc.values_by_name['ENUM_VALUE_A'].__dict__
{'index': 0, '_options_class_name': 'EnumValueOptions', 'name': 'ENUM_VALUE_A', '_options': None, 'type': <google.protobuf.descriptor.EnumDescriptor object at 0x10cfb6cd0>, 'number': 100, 'has_options': False}
(nice, looks like the 'number' attribute is what
we want)
>>> for k,v in desc.values_by_name.items():
... print("{} -> {}".format(k, v.number))
ENUM_VALUE_A -> 100
ENUM_VALUE_B -> 120
ENUM_VALUE_C -> 140
</code></pre>
<p>And there you have it, after a bit of digging into the internals of the protobuf generated code, we can easily get a dictionary containing the names (as strings) and values (as numbers) of all the entries in the enum.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p><a href="https://developers.google.com/protocol-buffers/docs/reference/python-generated#enum">https://developers.google.com/protocol-buffers/docs/reference/python-generated#enum</a><a href="#fnref:1" rev="footnote">↩</a></p></li>
</ol>
</div>
Playing Minecraft with a gamepad, a tutorial for Enjoy22013-09-25T00:00:00-07:00http://nongraphical.com/2013/09/playing-minecraft-with-a-gamepad-a-tutorial-for-enjoy2<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/nyko_controller.jpg" /></p>
<p>I like playing Minecraft, but after playing it for a couple of hours on a small 11-inch laptop, my wrists will start to hurt. I wanted to play Minecraft using a gamepad, like any console FPS, so I updated an open-source project to support mouse emulation and released <a href="https://github.com/fyhuang/enjoy2/">Enjoy2</a>. I'm not very experienced with OSX programming, though, so the user interface isn't as clear as it could be: the next version of Enjoy2 should hopefully make things a lot easier to use. In the meantime, here's a tutorial on how I set up Enjoy2 to control Minecraft with my aftermarket PS3 controller. (I don't own a PS3: I bought the controller specifically for PC gaming!) <a href="//nongraphical.s3-website-us-east-1.amazonaws.com/releases/Enjoy2.zip">Download Enjoy2 here</a> and try it yourself:</p>
<h2>Left analog stick</h2>
<p>The analog sticks are probably the weirdest part of the setup, so let's do that first. I like to have the left stick mapped to WASD and the right stick mapped to camera movement. With a controller plugged in, you should see something like this:</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/enjoy2_mc_1.png" /></p>
<p>The various buttons and sticks show up on the left, and what actions they map to show up on the right. On the very right side is a list of configurations, allowing you to set up different mappings for your different games. Move the left analog stick in a circle. Hopefully, you'll see two of the "Axis N" entries open up, like so:</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/enjoy2_mc_2.png" /></p>
<p>Move the stick slowly in the horizontal and vertical directions to figure out which one is which axis. Then, select the "Low" or "High" section of those axes. Finally, choose which key you want to press on the right side, in the box next to "Press a key:". "High" is activated when you have moved the axis far enough in one direction, and "Low" is activated for the other direction. On my controller, Axis 2 is vertical, so I have Low set to <code>W</code> and High set to <code>S</code>. Axis 1 is horizontal, so I have Low set to <code>A</code> and High set to <code>D</code>. "High" and "Low" are binary: when the axis (stick) is moved far enough, that action will activate (button will be pressed). Ignore the Analog sections.</p>
<h2>Right analog stick</h2>
<p>Let's do the right analog stick now. Do the same trick as above to figure out which axes correspond to the right stick--if there are only 4 axes in total, probably the two which you didn't map in the previous section. For these, since we want to have smooth camera control, we'll select the "Analog" settings on the left. Selecting "Analog" only works for mouse control, and means that if you move the axis a little bit off-center, the mouse moves slowly, and if you move the axis all the way to the edge, the mouse moves quickly. For me, Axis 3 is horizontal and Axis 4 is vertical. That means I've selected Axis 3 / Analog, and on the right side, selected Mouse movement: Horizontal. Similarly, I have mapped Axis 4 / Analog to Mouse movement: Vertical. Since we want analog movement, don't do anything with the High/Low settings on these axes. This will allow you to control the camera smoothly with the right stick, similarly to a console shooter. My Axis 3 setting looks like this:</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/enjoy2_mc_3.png" /></p>
<h2>Buttons</h2>
<p>Finally, we'll map the rest of the buttons. These are pretty easy: just press that button on your controller, and the corresponding "Button N" setting is selected. Then, as above, you simply select what you want to happen when that button is pressed. The "Toggle mouse scope" action deserves special mention, because it's quite relevant to Minecraft: Minecraft has, essentially, two mouse "modes". One is the mode where you don't have a cursor, and moving the mouse moves the camera. The other is the mode where you have the inventory or a chest or a menu open, and you can click on things with a cursor. Because of the way input works on OSX, these two modes require completely different ways of simulating mouse input. The "Toggle mouse scope" action tells Enjoy2 to switch mouse modes. I use the right bumper ("R1" in PS3 terminology, I think) for this action. Every time you open the inventory (circle/B for me), you have to remember to toggle the mouse mode (press R1). Unfortunately, I haven't found a better way to handle this mouse mode issue, but if you have any ideas, I would certainly like to hear them.</p>
<p>Hope you found this short tutorial useful! You can also <a href="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/enjoy2_mc_config.json">take a look</a> at my JSON config file, although it may not be of use to you unless you have my exact controller. Here's the <a href="//nongraphical.s3-website-us-east-1.amazonaws.com/releases/Enjoy2.zip">download link for Enjoy2</a> again. Have fun playing Minecraft with a controller!</p>
A more awesome way to play Bananagrams2013-09-14T00:00:00-07:00http://nongraphical.com/2013/09/a-more-awesome-way-to-play-bananagrams<p class="post_updated">Update: my friend Cole was at the same game night and he <a href="https://medium.com/p/3ba977a307e2">also wrote about this variation</a>.</p>
<p>My friends and I discovered a new ruleset for playing <a href="http://en.wikipedia.org/wiki/Bananagrams">Bananagrams</a><sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> which I think makes the game super awesome. We're a bunch of tactical boardgame-lovers, and these altered rules make (I think) the game much more fun for boardgame players. First, the rules<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>:</p>
<ol>
<li>Players start with 5 tiles each.</li>
<li>When a player uses all of their letters in a single connected component, that player says 'peel'. When a peel occurs, all other ("non-peeling") players give one tile of their choice to the peeling player, and take one tile from the supply. The peeling player receives tiles from non-peeling players, but takes nothing from the supply.</li>
<li>As in the original, players can rearrange the tiles in front of them at any time. When a peel occurs, you may choose to give up a tile which is already in a connected component, or not.</li>
<li>The game ends when a peel is called but there are not enough letters in the supply for everyone.</li>
<li>The player who has the largest single connected component at the end of the game wins.</li>
<li>No dumping is allowed.</li>
</ol>
<p>There's a detailed example later on, with images, that shows one play-through of the game with these new rules. We've tried this variation with 4 and 8 players: it works beautifully in the 4-player case, and for 8-players, split the players into two "peel groups". When a peel happens, only the players in the peeling player's group give them tiles. This prevents too much confusion from 7 people all trying to give tiles at once. The supply can remain shared between the two groups. These rules should work for 3- to 8-player games (split into two peel groups at 6 players); we have yet to work out a good solution for two players, since the total circulating (not in the supply) tiles will not increase in that case.</p>
<p>Here's a more detailed example, with images, of a play-through of Bananagrams using our custom rules:</p>
<table>
<tr>
<td><img class="caption" src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/bananagrams_1.png" title="1. Everyone starts with 5 tiles" /></td>
</tr><tr>
<td><img class="caption" src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/bananagrams_2.png" title="2. The game starts, players try to connect their tiles together into words" /></td>
</tr><tr>
<td><img class="caption" src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/bananagrams_3.png" title="3. Alice connects everything and says 'peel'" /></td>
</tr><tr>
<td><img class="caption" src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/bananagrams_4.png" title="4. Everyone gives Alice a tile" /></td>
</tr><tr>
<td><img class="caption" src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/bananagrams_5.png" title="5. Everyone except Alice takes a tile" /></td>
</tr><tr>
<td><img class="caption" src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/bananagrams_6.png" title="6. The game continues until someone says 'peel', but there aren't enough tiles left in the center" /></td>
</tr><tr>
</tr>
</table>
<p>In this example game, Alice starts out strong with the first "peel". Bob and Charlie each give Alice one tile of their choice, and then each take one tile from the supply in the center. The players continue to rearrange their tiles and say "peel" until the supply runs out of tiles. In the sixth image, Charlie says "peel" but there is only one tile left in the supply, and both Alice and Bob would need a tile. Thus, the game ends. In normal Bananagrams, Charlie would be the winner, since he peeled last, but in our version, Bob wins, since his "crossword" is the largest. (Bob has 10, Charlie has 7, and Alice has 8.) Note that the tiles which the players haven't been able to incorporate (U,Z,P) don't count toward the winning score.</p>
<p>This variation has some nice properties that we enjoy which are lacking in the original ruleset. First, the gameplay becomes much slower. This gives it a nice "cerebral" feel. The game no longer feels frantic or rushed, but still with a sense of urgency. Second, these rules make the game more self-balancing. Peeling is required to win the game--it's the only way to increase the number of tiles in front of you, and thus to build the largest connected component--but peeling also slows you down, since you now need to incorporate several new tiles from the other players. When a peel happens, other players are also given a chance to replace one of their tiles with a possibly-better one from the supply. Finally, these rules separate the game-end condition from the win condition. The game ends when the supply runs out, but the person who peeled last is not necessarily the person who wins. This makes the winner less arbitrary, as progress you make during the game--collecting more tiles to make a larger crossword--now significantly influences your chance of winning.</p>
<p>It's also interesting to note that the difficult-to-use tiles (e.g. 'Q', 'X') don't necessarily always stay in limbo. In our games, they often get incorporated into components and are then not easily given up when peeling. I hope you'll find this variation on Bananagrams to be just as much fun as we have--if you try out this ruleset, let me know what you think!</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>The author and his friends are, of course, in no way affiliated with Bananagrams the company.<a href="#fnref:1" rev="footnote">↩</a></p></li>
<li id="fn:2">
<p>What to do in corner cases: when two players peel at the same time, it counts as two separate peels. Don’t forget to incorporate the tile you received from someone else’s peel before you say ‘peel’ yourself. A draw may be broken at the end of the game by declaring the player who has the least number of non-connected tiles the winner. When the last ‘peel’ happens, the game stops immediately: no more rearrangements can be made, and no tiles are transferred or taken from the supply.<a href="#fnref:2" rev="footnote">↩</a></p></li>
</ol>
</div>
Enjoy2 v1.2 released: control games with your gamepad on OSX2013-05-06T00:00:00-07:00http://nongraphical.com/2013/05/enjoy2-v12-released-control-games-with-your-gamepad-on-osx<p class="post_updated">Update: I have written a quick tutorial for <a href="http://nongraphical.com/2013/09/playing-minecraft-with-a-gamepad-a-tutorial-for-enjoy2/">setting up Minecraft with Enjoy2</a>.</p>
<p>Enjoy2 is my <a href="http://nongraphical.com/2012/08/enjoy2-mapping-joystick-inputs-to-keyboard-and-mouse-events/">gamepad/joystick to keyboard and mouse mapper for OSX</a>. Version 1.2 of Enjoy2 features some small bugfixes, as well as a change in the configuration format. Before, Enjoy2 stored configurations as user preference data. Now, configurations are stored as plain-text JSON files in an easily accessible directory (<code>~/Library/Application Support/Enjoy2</code>), to make it easy to transfer mappings from one computer to another. If you have a game that only supports mouse and keyboard as input, but you would like to play with a gamepad, try Enjoy2 and see if it works for you. Personally, I use it to play <a href="http://minecraft.net">Minecraft</a> with less wrist fatigue.</p>
<p>You can always <a href="//nongraphical.s3-website-us-east-1.amazonaws.com/releases/Enjoy2.zip">download the latest release of Enjoy2 using this link</a>. You can also <a href="https://github.com/fyhuang/enjoy2">check out the source code on GitHub</a>. Let me know if Enjoy2 is useful for you!</p>
bottle.py: use get_url from any template file2013-05-05T00:00:00-07:00http://nongraphical.com/2013/05/bottlepy-use-get_url-from-any-template-file<p>A quick tip for setting default/global template variables in <a href="http://bottlepy.org/">bottle.py</a>: in my <a href="http://nongraphical.com/2012/08/using-bottle-py-in-production/">previous bottle.py post</a>, I mentioned <code>get_url</code>, a very useful function for generating urls in a url-agnostic app. (That means you can mount your app at any url prefix, e.g. <code>http://mywebsite.com/blog/</code>.) Here's a way to call <code>get_url</code> from within your SimpleTemplate templates. When using SimpleTemplate, bottle.py offers a way (undocumented) of setting default (global) variables in template files through the <code>BaseTemplate.defaults</code> class variable:</p>
<pre><code>BaseTemplate.defaults['symbol_name'] = value
</code></pre>
<p>To use <code>get_url</code> from any template, you can put <code>get_url</code> in the default global variables:</p>
<pre><code>app = bottle.default_app()
BaseTemplate.defaults['get_url'] = app.get_url # reference to function, not function call!
</code></pre>
<p>Now you can simply call <code>get_url</code> from your templates:</p>
<pre><code><a href="{{ get_url('namedroute') }}">my link</a>
</code></pre>
Decimal time in your Bash prompt2013-03-27T00:00:00-07:00http://nongraphical.com/2013/03/decimal-time-in-your-bash-prompt<p>While testing <a href="https://github.com/fyhuang/flight_price/"><code>flight_price</code></a>, I would run into this problem where I would start a <code>record_prices</code> command, go do something else, come back, and want to know how long the command had been running for. I wanted a way to include a short string representing the current time in my <code>bash</code> prompt unintrusively. The <code>record_prices</code> command can take upwards of an hour to complete, so the <a href="http://en.wikipedia.org/wiki/Decimal_time">decimal time</a> representation, especially the 1/1000ths of a day representation used by <a href="http://en.wikipedia.org/wiki/Swatch_Internet_Time">Swatch Internet Time</a>, seemed like a perfect fit. It's granular enough to display how many minutes have elapsed since I started running the command, but compact enough to not take up precious screen space in my prompt.</p>
<p>I wrote a simple little utility, <a href="dt"><code>dectime</code></a>, to print the current time in decimal, and to convert decimal times back into "normal" times. Putting the <a href="dt"><code>dectime</code></a> on the left side of the prompt looked weird, so I decided to try right-aligning it. This is the prompt code I ended up using:</p>
<p>```bash</p>
<h1>Excerpt from ~/.bashrc</h1>
<p>function right_align_time {
printf "%*s\r" $(( COLUMNS-1 )) "@<code>dectime</code>"
}</p>
<p>PS1="\$(right_align_time)[\u@\h \W]\$ "
```</p>
<p>The <code>\$(right_align_time)</code> part instructs <code>bash</code> to re-execute the <code>right_align_time</code> function every time the prompt is printed. <code>right_align_time</code> uses <code>printf</code> to right-align the output (using the <code>$COLUMNS</code> variable) and prints <code>@</code> followed by the output of <a href="dt"><code>dectime</code></a>. <sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> If you want to use <a href="dt"><code>dectime</code></a> on your machine, it's just a single <code>.cpp</code> file and should compile easily with no dependencies on any *nix machine. Here's what my terminal looks like with <a href="dt"><code>dectime</code></a> added:</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/2013/terminal_with_dectime.png" /></p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>This technique is from <a href="http://stackoverflow.com/questions/7697889/how-to-show-git-status-info-on-the-right-side-of-the-terminal">http://stackoverflow.com/questions/7697889/how-to-show-git-status-info-on-the-right-side-of-the-terminal</a><a href="#fnref:1" rev="footnote">↩</a></p></li>
</ol>
</div>
A utility for data mining flight prices2013-03-25T00:00:00-07:00http://nongraphical.com/2013/03/a-utility-for-data-mining-flight-prices<p>In August, my girlfriend will be starting medical school in Colorado, and I will be here in San Francisco. Naturally, I have been looking at plane tickets between SF and Denver, and I noticed that, contrary to my expectation, flight prices followed a non-monotonic function of the number of weeks in advance I searched. I expected that flight prices would monotonically get more expensive as the flight date got closer, but I found that the pattern was something like this:</p>
<ul>
<li>3+ months before the flight date, the prices are in a "steady state" with little change.</li>
<li>Somewhere around 1.5-3 months before the flight date, there is a noticeable dip in prices (the tickets get cheaper).</li>
<li>As the flight date nears to within a week or two, prices get much higher.</li>
</ul>
<p>My hypothesis is there are at least two semi-independent variables affecting the price of an airline ticket. One is the amount of time before the flight date you search for the ticket. This, as I had observed, seems to have a local minimum at 1.5-3 months. I suspect that the actual flight date itself will be another factor: flights around Christmas and July 4th should be more expensive, all other things equal (tentatively called the ticket's "intrinsic price"). I wanted to test this hypothesis by gathering actual data on ticket prices, and to aid me in the process of mining ticket prices I created a tool named (so creatively) <a href="https://github.com/fyhuang/flight_price/"><code>flight_price</code></a>.</p>
<p><a href="https://github.com/fyhuang/flight_price/"><code>flight_price</code></a> is a collection of <a href="http://casperjs.org/">CasperJS</a> scripts and some Python wrappers to automatically retreive and record flight prices. When you run it, it collects information about airline tickets serving your specified route for the next six months. It then stores that ticket information in a database. I am releasing an "alpha quality" version of this today, which you can use with your own routes and days, but once I have collected a few months of information, I will update <code>flight_price</code> to use the collected data and perform some basic analyses on it. Hopefully that will allow me to characterize the "intrinsic price" of an airline ticket, and determine exactly how many weeks in advance I should buy plane tickets for maximum savings.</p>
Using ifplugd to resolve NAS booting problems2012-10-05T00:00:00-07:00http://nongraphical.com/2012/10/using-ifplugd-to-resolve-nas-booting-problems<p class="post_updated">Updated March 2013 to include configuration files for `ifplugd`.</p>
<p>A year or two ago, I built a small Linux server for use as a NAS (network attached storage) and router. It evolved through a number of iterations, but in its latest configuration is running a fairly vanilla Arch Linux. There was one problem that kept bugging me when I moved it to a new residence/network, though--it always refused to finish the booting process the first time that I plugged it in. Because I have it set up as a NAT router, with two ethernet ports, I would try to debug the situation by plugging my laptop into the "LAN" side port. When I did that, the machine would have no problems at all booting up. The problem was exacerbated because I ran the server headless, and it would not finish bringing up the WAN side interface before it froze, so I couldn't even open an SSH session to see what was going on.</p>
<p>I eventually traced the problem to a quirk of the Arch Linux boot scripts. I am using <code>net-profiles</code>, so I have <code>internal</code> and <code>external</code> profiles in <code>/etc/network.d</code>. <code>internal</code> was set to a static IP address, and <code>netcfg</code> wouldn't allow the boot to continue if no cable was plugged into the port for internal. This explains both the booting problem and the symptom that it would magically work after I plugged in my laptop.</p>
<p>By searching the Arch forums, I found <a href="http://0pointer.de/lennart/projects/ifplugd/"><code>ifplugd</code></a>, which automatically brings up/takes down network interfaces depending on the media presence. It's useful for laptops which have the ethernet cable frequently connected or disconnected, but it has also come in handy in my situation. Instead of letting Arch start my network interfaces automatically, I set them to use <code>ifplugd</code> instead. If the media are connected at boot, <code>ifplugd</code> will bring up the respective interfaces, but if (for example) the internal interface is not connected to anything, <code>ifplugd</code> won't bring it up (until it is connected). This neatly solves my problem, and ifplugd is already available in Arch repository <code>extra</code>. I used this this configuration, which also starts/stops <code>dnsmasq</code>, a DNS/DHCP server, with the internal interface:</p>
<div class="highlight"><pre><code class="bash"><span class="c"># /etc/ifplugd/ifplugd.conf</span>
<span class="nv">INTERFACES</span><span class="o">=</span><span class="s2">"eth0 eth1"</span>
<span class="c"># Run this script when a cable is plugged/unplugged</span>
<span class="nv">ARGS</span><span class="o">=</span><span class="s2">"--run=/etc/ifplugd/net_dnsmasq.action"</span>
</code></pre></div>
<p>Here's the action file:</p>
<div class="highlight"><pre><code class="bash"><span class="c"># /etc/ifplugd/net_dnsmasq.action</span>
<span class="c">#!/bin/bash</span>
<span class="c"># $1=[eth0|eth1], $2=[start|stop]</span>
/etc/ifplugd/netcfg.action <span class="nv">$1</span> <span class="nv">$2</span>
<span class="nv">NETCFG_RETURN</span><span class="o">=</span><span class="nv">$?</span>
<span class="c"># Start/stop dnsmasq if eth1</span>
<span class="k">if</span> <span class="o">[[</span> <span class="s2">"$1"</span> <span class="o">==</span> <span class="s2">"eth1"</span> <span class="o">]]</span>; <span class="k">then</span>
<span class="k"> case</span> <span class="s2">"$2"</span> in
up<span class="o">)</span>
systemctl start dnsmasq
;;
down<span class="o">)</span>
systemctl stop dnsmasq
;;
<span class="k">esac</span>
<span class="k">fi</span>
<span class="nb">exit</span> <span class="nv">$NETCFG_RETURN</span>
</code></pre></div>
<p><code>netcfg.action</code> is included with the Arch package for <code>ifplugd</code> (it determines the appropriate network profile for an interface and starts/stops it accordingly). The script I wrote, <code>net_dnsmasq.action</code>, is just a simple wrapper for the included <code>netcfg.action</code> which starts/stops <code>dnsmasq</code> as appropriate.</p>
Using bottle.py in production2012-08-24T00:00:00-07:00http://nongraphical.com/2012/08/using-bottle-py-in-production<p class="post_updated">Update: I wrote <a href="http://nongraphical.com/2013/05/bottlepy-use-get_url-from-any-template-file/">a post about how to call get_url from within a SimpleTemplate template</a>. The same technique works to make any Python variable or function you want globally accessible by default from a SimpleTemplate template.</p>
<p>This is a quick guide to using <a href="http://bottlepy.org/">bottle.py</a> in a (semi-)production environment with lighttpd. Bottle.py is a super-lightweight (one source file!) web framework for Python which I use for quick, single-purpose web scripts. For example, I have used Bottle.py for small web applications to:</p>
<ul>
<li>Monitor CPU and HDD temps</li>
<li>Provide a quick and easy personal file drop location</li>
<li>Administer hg repositories</li>
</ul>
<p>This guide will show some techniques to write a URL-agnostic app in Bottle.py and then deploy it, using FCGI and lighttpd. Requirements:</p>
<ul>
<li>python>=2.7</li>
<li>bottle.py>=0.10</li>
<li>flup</li>
</ul>
<h2>Bottle.py tips</h2>
<h3>get_url</h3>
<p>Use the <code>get_url</code> function to write a URL-agnostic app. With <code>get_url</code>, you can mount your app at any root URL on your server. For example, if your app handles the <code>/viewpost</code> and <code>/listposts</code> URLs, and you mount it at <code>http://mywebsite.com/blog/</code>, the final URLs that you would access from your web browser would be <code>http://mywebsite.com/blog/viewpost</code> and <code>http://mywebsite.com/blog/listposts</code>. You can only use <code>get_url</code> with named routes:</p>
<pre><code>import bottle
app = bottle.default_app()
@app.route('/viewposts', name='viewposts')
def handle_viewposts():
return 'first post!'
# Calling get_url from handle_index
@app.route('/index')
def handle_index():
return '<a href="{}">View posts</a>'.format(app.get_url('viewposts'))
</code></pre>
<p>You can also use <code>get_url</code> for dynamic routes (routes with parameters):</p>
<pre><code>@app.route('/get/<name:path>', name='getobj')
def handle_getobj(name):
return bottle.static_file(name, root='/path/to/files')
# Call get_url like this
url = app.get_url('getobj', name='filename.txt')
</code></pre>
<h2>Deploying with flup</h2>
<p>Usually I deploy Python web apps with <a href="http://trac.saddi.com/flup">flup</a> (there's also a <a href="http://hg.saddi.com/flup-py3.0">Python 3 version</a>). I use FastCGI on a Unix socket, running behind lighttpd. For these examples, assume that the app socket is called <code>/run/lighttpd/myapp.sock</code>.</p>
<h3>Python configuration</h3>
<p>For Python 2.7 and flup, use Bottle's builtin flup server, setting the <code>bindAddress</code> to the path to the socket:</p>
<pre><code>if __name__ == "__main__":
run(server='flup', options={'bindAddress': '/run/lighttpd/myapp.sock'})
</code></pre>
<h3>lighttpd</h3>
<p>Make sure <code>mod_fastcgi</code> is loaded in your config. To mount an FCGI Bottle app at some URL, say <code>/myapp</code>, add this to your lighttpd.conf:</p>
<pre><code>fastcgi.server = (
"/myapp" => (
"myapp-fcgi" => (
"socket" => "/run/lighttpd/myapp.sock",
"check-local" => "disable",
"docroot" => "/",
)
)
)
</code></pre>
<p>Disabling <code>check-local</code> allows your app to handle URL requests even if a file of the same name does not exist on the local filesystem. For more information on lighttpd and FastCGI, see the <a href="http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModFastCGI">official documentation</a>.</p>
Enjoy2: mapping joystick inputs to keyboard and mouse events2012-08-02T00:00:00-07:00http://nongraphical.com/2012/08/enjoy2-mapping-joystick-inputs-to-keyboard-and-mouse-events<p class="post_updated">Update 2: I've written a <a href="http://nongraphical.com/2013/09/playing-minecraft-with-a-gamepad-a-tutorial-for-enjoy2/">short tutorial</a> for using Enjoy2 to map a PS3/Xbox-style gamepad for Minecraft.</p>
<p class="post_updated">Update: I have released a minor update, <a href="http://nongraphical.com/2013/05/enjoy2-v12-released-control-games-with-your-gamepad-on-osx/">Enjoy2 v1.2</a>, which stores the configuration files as portable JSON files. This makes it much easier to transfer configurations between computers and between user accounts. Use your gamepad to control video games on multiple computers!</p>
<p><a href="https://github.com/fyhuang/enjoy2/">Enjoy2</a> is a small OSX program to map joystick/gamepad/controller inputs to keyboard and mouse events. I wanted to play some video games (<a href="http://www.minecraft.net/">Minecraft</a>, <a href="http://www.torchlightgame.com/">Torchlight</a>) on my computer with a gamepad (I find it less fatiguing than a mouse), but neither of those games supports gamepads or controllers natively. <a href="https://github.com/fyhuang/enjoy2/">Enjoy2</a> makes it possible to play these and other mouse/keyboard-only games with a gamepad.<!--more--> The only FOSS solution to this problem I could find online was the original <a href="http://abstractable.net/enjoy/">enjoy</a>, which supports mapping:</p>
<ul>
<li>Buttons to keyboard events</li>
<li>Buttons to switch configurations</li>
</ul>
<p>And which can also map the ends of the analog axes (i.e. triggered based on a threshold value) to those actions. Unfortunately enjoy has no mouse support, so I started a new project based on it which aims to add:</p>
<ul>
<li>Analog axes mapping to mouse movement</li>
<li>Buttons mapping to mouse clicks</li>
</ul>
<p>Because I am running OS X 10.7, I could only compile Enjoy2 for Snow Leopard (OS X 10.6) systems or newer. Check out the <a href="https://github.com/fyhuang/enjoy2">GitHub repository</a> or <a href="//nongraphical.s3-website-us-east-1.amazonaws.com/releases/Enjoy2.zip">get the latest version of Enjoy2 now</a>.</p>
Wordpress vs static HTML on shared hosting2012-07-24T00:00:00-07:00http://nongraphical.com/2012/07/wordpress-vs-static-html-on-shared-hosting<p>One of the reasons I started writing <a href="https://github.com/fyhuang/makeblog">makeblog</a> was because I use shared hosting and felt like I needed more speed than Wordpress and fewer features. So I wrote makeblog with the intention of providing a fairly minimal but complete blog implementation. Today I got around to benchmarking Wordpress (what my blog previously ran on) against the static HTML pages generated by makeblog. Results with Wordpress:</p>
<pre><code>Document Length: 41435 bytes
Concurrency Level: 10
Time taken for tests: 69.079 seconds
Requests per second: 1.45 [#/sec] (mean)
Transfer rate: 59.18 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Total: 1689 6722 1844.6 6439 14825
Percentage of the requests served within a certain time (ms)
50% 6439
...
100% 14825 (longest request)
</code></pre>
<!--more-->
<p>Results with makeblog (static HTML pages):</p>
<pre><code>Document Length: 11812 bytes
Concurrency Level: 10
Time taken for tests: 6.994 seconds
Requests per second: 14.30 [#/sec] (mean)
Transfer rate: 169.11 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Total: 382 691 145.5 740 873
Percentage of the requests served within a certain time (ms)
50% 740
...
100% 873 (longest request)
</code></pre>
<p>Due to a new website layout, the Wordpress-generated index file is 4x the size of the makeblog-generated index file; however, the request time for Wordpress is 10x that of the static HTML pages. It's not just the relative speedup that's significant though; the original Wordpress setup could take up to 14 <strong>seconds</strong> to display the front page to a first-time visitor, while with the static HTML pages we have reduced the maximum load time to under a second. Now performance is acceptable even for first-time visitors without anything in cache.</p>
<p>These results were generated using Wordpress and makeblog on a Joyent shared hosting server, and tested from the same connection. Recently I switched to Arvixe shared hosting, and the results from that server are as follows:</p>
<pre><code>Concurrency Level: 10
Time taken for tests: 3.411 seconds
Requests per second: 29.32 [#/sec] (mean)
Transfer rate: 425.39 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Total: 205 333 63.6 352 425
Percentage of the requests served within a certain time (ms)
50% 352
...
100% 425 (longest request)
</code></pre>
<p>Obviously, it's hard to beat static HTML pages in terms of speed, but soon I will post benchmarks of my blog running on static HTML pages and running on the lightweight WSGI app I am working on to support commenting. If you have a lightweight blog, go ahead and give <a href="https://github.com/fyhuang/makeblog">makeblog</a> a try; it can even import your existing Wordpress database for a seamless transition.</p>
Is C++ worth it, for video games?2012-07-24T00:00:00-07:00http://nongraphical.com/2012/07/is-cc-worth-it-for-video-games<p>I really like the <a href="http://lemire.me/blog/archives/2012/07/23/is-cc-worth-it/">viewpoint</a> that <a href="http://lemire.me/">this guy</a> takes to using C++:</p>
<blockquote><p>Really clever and hard working C/C++ programmers can beat higher-level languages by a wide margin given enough time. However, their code will typically become less portable and harder to maintain.</p>
<p><strong>Conclusion:</strong> If your sole reason for using C++ is speed, and you lack the budget for intensive optimization, you might be misguided.</p></blockquote>
<p>Especially that last line. I conjecture that the thought pattern for people resisting moving to higher-level languages looks like this:</p>
<ol>
<li>Write some code in Python (Lua, C#, Ruby, etc.)</li>
<li>Runs slow</li>
<li>Write same code in C/C++</li>
<li>Compile with -O3, runs fast!</li>
<li>Conclusion: Python (Lua, C#, Ruby) is too slow.</li>
</ol>
<p>Of course, the conclusion only follows <a href="http://en.wikipedia.org/wiki/Modus_ponens">if the premises are true</a>, and here I think low-level language people get caught on step 1. Often C/C++ programmers write their Python code <em>as if they were writing C</em>, but if you write Python like this:</p>
<pre><code>in_list = [1,2,3,...]
sum = 0
ix = 0
while ix < len(in_list):
sum += in_list[ix]
print(sum)
</code></pre>
<p>Then of course you shouldn't expect it to run fast. I agree with @lemire on his general conclusion: if you're not going to seriously micro-optimize, think about using something else. For most realistic-sized projects (say, more than 10k lines), you'll end up saving yourself time and effort.</p>
<h2>But what about video games?</h2>
<p>Unfortunately it's hard to get away from C++ when you're writing video games. Why? All the useful libraries (<a href="http://www.ogre3d.org/">Ogre</a>, for example) are in C++. The Python port of Ogre is hairy, and Ogre isn't built for non-compiled languages anyways (it's very hard to test Ogre code in Python). It's even difficult to access the low-level APIs (e.g. OpenGL) in high-level languages, due to their reliance on C-isms.</p>
<p>What can we high-level language users do about this? Write more game engines, game middleware, and game libraries in your language of choice! Personally, I am recently enamoured of <a href="http://golang.org/">Go</a> and am thinking about writing a video game-focused DSL based on Go. There are some things (vectors, matrices, the concept of space and time) which are common to almost all video games and should be made first-class in a language. If this sounds cool, <a href="http://nongraphical.com/about/">let me know</a>!</p>
Cloudsourcing comments with Disqus2012-07-06T00:00:00-07:00http://nongraphical.com/2012/07/cloudsourcing-comments-with-disqus<p>While tinkering around with a "semi-static" architecture for <a href="https://github.com/fyhuang/makeblog">makeblog</a> in an effort to support commenting, I discovered <a href="http://disqus.com/">Disqus</a>, a cloud-based commenting system. This was the perfect complement to my static HTML-based makeblog, and I have now enabled it on all the posts on this site. One great thing about using a cloud-based service like Disqus is that you get separation between <em>publishing</em> and <em>commenting</em>. <!--more-->makeblog is at its core a <em>publishing</em> system--you write posts, it turns them (publishes them) into nice-looking static HTML pages which you can serve on the Internet, put in a zipfile, whatever you want. Makeblog is structured to let you keep your posts, drafts, and other publishing-related data on disk, so you can keep it in version control. I was exploring a text format for comments on disk, but having that really wreaks havoc with the nice, simple version-controlled posts concept. Instead, using Disqus presents a very nice modular solution to the problem. Now, if only we could integrate other services as easily into our blogs, like photo galleries...</p>
<p>By the way: this doesn't mean I'm giving up on the dynamic aspect of makeblog entirely. I will be releasing a "light" commenting system in makeblog using <a href="http://flask.pocoo.org/">Flask</a> soon.</p>
How to survive a Chinese internet cafe2012-06-06T00:00:00-07:00http://nongraphical.com/2012/06/how-to-survive-a-chinese-internet-cafe<p>Most hotels in major Chinese cities now offer free wifi, but what if you're traveling a bit off the beaten path or didn't bring a computer? One of the most convenient options for getting online is to use an internet cafe. I keep a USB stick for this exact purpose, here's what I have on it:</p>
<ul>
<li>PuTTY Portable</li>
<li>Firefox Portable</li>
<li>A .pac file</li>
<li>(Optional) SumatraPDF portable</li>
</ul>
<p>Essentially, the USB stick contains all the necessary ingredients for a SSH tunnel proxy. All of the software are <a href="http://portableapps.com/">Portable Apps</a>. Use as follows:</p>
<ol>
<li>Set up an SSH dynamic tunnel to a host of your choice--I'm a Stanford student, so <code>myth.stanford.edu</code> works well for this purpose. (You can find instructions <a href="http://www.dotcomunderground.com/blogs/2008/12/11/putty-ssh-tunnel-to-hide-ip/">online</a>.) Just make sure the host is outside of China.</li>
<li>Configure Firefox to use the tunnel either directly or using the PAC file. The PAC file is very convenient for long-term use in countries like China, where certain sites (e.g. Baidu, Weibo, Youku etc.) should be accessed direct and others (Facebook, YouTube) should be accessed through the proxy. I've included an example PAC file below, of course, be sure to change the site lists to taste.</li>
<li>Browse the internet!</li>
</ol>
<p>Example PAC file which includes several Chinese sites:</p>
<pre><code>function FindProxyForURL(url, host) {
var direct_sites = [
'localhost',
'192.168.*',
'*.cn',
'baidu.com',
'*.baidu.com',
'*.bdstatic.com',
'*.bdimg.com',
'renren.com',
'*.renren.com',
'*.xnimg.com',
'weibo.com',
'*.weibo.com',
'youku.com',
'*.youku.com',
'*.ykimg.com',
'*.tudou.com'
];
for (var i = 0; i < direct_sites.length; i++) {
if (shExpMatch(host, direct_sites[i])) {
return "DIRECT";
}
}
// This will change depending on how you set up your tunnel
var proxy_url = "SOCKS5 127.0.0.1:9876";
var proxy_sites = [
'facebook.com',
'*.facebook.com',
'youtube.com',
'*.youtube.com',
'google.com',
'www.google.com'
];
for (var i = 0; i < proxy_sites.length; i++) {
if (shExpMatch(host, proxy_sites[i])) {
return proxy_url;
}
}
return proxy_url + ";DIRECT";
}
</code></pre>
Scripting a Website Scraper2012-05-24T00:00:00-07:00http://nongraphical.com/2012/05/scripting-a-website-scraper<p>This is a follow-up to my previous post, <a href="http://nongraphical.com/2012/05/please-learn-to-script/">Please learn to script?</a>. A friend needed to get a list of companies in Beijing for a research project. <a href="http://www.alibaba.com/">Alibaba</a> has a list of such companies, but getting the information requires manually clicking through all 90 pages of results and copying-pasting each link. This was a perfect application of the <a href="http://nongraphical.com/tag/automation/">automation</a> I talked about last time--writing a simple script to let the computer do the dirty work. Here's one script that could be used for that purpose:</p>
<pre><code># Outputs tab-separated file of company names and links
import re
import time
import requests
listitem_re = re.compile('\s*<a id="lsubject_(\d+)" onmousedown="(.*)" href="(?P<href>http://.*)" onclick="(.*)" title="(?P<title>.*)" target="_blank">')
with open('output.txt', 'w') as outfile:
outfile.write('Name\tLink\n')
for p in range(1,91):
url = "http://www.alibaba.com/corporations/beijing/--CN------TR1------------------OFFSET1/{}.html".format(p)
r = requests.get(url)
if r.status_code == 404:
print("URL {} not found!".format(url))
break
lines = r.text.splitlines()
for l in lines:
m = listitem_re.match(l)
if m is not None:
title = m.group('title').replace('&amp;', '&')
outfile.write('{}\t{}\n'.format(title, m.group('href')))
print("Processed page {}".format(p))
</code></pre>
<!--more-->
<p>The script is made slightly simpler by Alibaba's convenient handling of search URLs: the search query seems to be in the part with the dashes, and simply putting a <code>{number}.html</code> after it gets you the results page.</p>
<h2>What about beginner scripters?</h2>
<p>If a person learning to script were to write this script, the following might be some difficult points:</p>
<ul>
<li><code>listitem_re</code>: regular expressions are hard, this would be difficult for a beginner programmer. I wish we had a less opaque method of English text processing.</li>
<li><code>with open(...) as f</code>: it would also be fine if the scripter wrote <code>outfile = open(...)</code> then later <code>outfile.close()</code>. Not as Pythonic but maybe more likely to show up in beginner Python tutorials.</li>
<li><code>for p in range(1,91): url = ".../{}.html".format(p)</code>: this is a trick that a beginner might have trouble coming up with immediately.</li>
<li><code>r = requests.get(url)</code>: script writer needs to know about the excellent <a href="http://www.python-requests.org">Requests</a> framework.</li>
<li><code>if r.error_code == 404</code>: would work fine without this error-checking.</li>
<li><code>m = listitem_re.match(l)</code>: again, REs are hard, but this is one of the simplest uses of regular expressions.</li>
</ul>
<p>Regular expressions are the most difficult thing about this "assignment", but with the help of an experienced mentor (or maybe Stack Overflow), this script should <strong>certainly be within reach</strong> of a budding script-writer.</p>
<p>The ability to write scripts like this, or at least the ability to recognize when scripting can be useful, <em>is the difference between days of tedious "manual labor" and a few minutes of hacking</em> together a quick script and <em>getting the job done</em>.</p>
4 cases of treating the symptoms2012-05-20T00:00:00-07:00http://nongraphical.com/2012/05/4-cases-of-treating-the-symptoms<p>Lately I have been thinking about various problems for which the "simple, direct solution" had negative effects. In particular, a problem that China is currently experiencing (warning: unsubstantiated claims ahead): <strong>city traffic.</strong> China's traffic problem is very serious right now and the government understands that fact. Unfortunately, their solutions have been too direct--i.e. completely ignored the underlying cause of the problems. Too many cars on the road?</p>
<p><em>Solution: make it illegal to drive cars with certain license plate numbers on certain days.</em> This has had the unfortunate and rather ironic side effect of encouraging people to buy multiple cars in order to circumvent the block.<!--more--> (Many car buyers in China are exceedingly rich, and own a car more for displaying social status than for transportation.)</p>
<p><em>Solution: make it harder to buy a car by having a lottery for car-purchasing rights.</em> Now people who didn't even particularly want to buy a car before enter the lottery because they don't want to lose their chance to buy a car forever (or for a long time). Net result: more people wanting to buy cars, and a higher social status & desirability for people who own them (one of the reasons for the explosion of car-ownership in China, as mentioned above).</p>
<p>These solutions try to impose a certain result <strong>without understanding the underlying social structures that have contributed to the undesirable result.</strong> This is, of course, not limited to China; Western countries make the same kinds of mistakes. Most notably: want to introduce the deprived citizens of the Middle East to democracy? <em>Depose the dictator by force and institute a democratic government.</em> Simply forcing a democratic government on a people, interestingly, doesn't necessarily give them a democratic government.</p>
<p>A final example from Stanford. In front of the entrance to the Gates CS building is a wide sidewalk. Many students using this entrance park their bikes on the sidewalk nearby, ignoring the farther-away bike racks (which don't have enough capacity for the volume of students to Gates anyways). Stanford would like students to park in bike racks rather than on the sidewalk. <em>Solution: they have an official-looking person come by every day and tag bikes with a "this is illegal, move your bike or we will impound it" sign.</em> Obviously this doesn't do anything to improve the bike parking situation, and is blatant symptom-treating without any attempt to remedy the underlying cause (not enough bike parking in useful places).</p>
<p>(Note on unsubstantiated claims on traffic in China: from anecdotal reports I feel good about claiming the above, but as this is China, true results of government policies are hard to dig up.)</p>
Please learn to script?2012-05-16T00:00:00-07:00http://nongraphical.com/2012/05/please-learn-to-script<p>This is a somewhat humorous response to the recent (don't) learn to code debates on Hacker News (arguments <a href="http://www.codinghorror.com/blog/2012/05/please-dont-learn-to-code.html">against</a> and <a href="http://sachagreif.com/please-learn-to-code/">for</a>). I'm here to advocate a somewhat perpendicular viewpoint, which is that scripting is the thing we should be worrying about, not coding.</p>
<!--more-->
<p>Before I say anything further we have to establish a target audience. "Computer skills" is another issue entirely, so let's say that our target users have a basic understanding of how to use a computer: drag-and-drop, some concept of files and folders, how to use a web browser, that kind of thing. Perhaps the user uses a computer regularly for schoolwork but isn't familiar with advanced MS Word commands, whatever. For convenience, I'm going to call this person the "normal" user.</p>
<p>The reason I want to make a trivial terminological distinction here between "coding" and "scripting" is because I want to talk about a specific final goal. My question is: "what's so useful about computers?" For the normal user, a computer is kind of like a third arm, it makes certain things in life easier. For example:</p>
<ol>
<li>Moving files around on a computer is easier than moving piles of paper around in real life.</li>
<li>Sending email takes less effort than writing a letter, stamping it, and putting it in a mailbox.</li>
<li>Word processing makes it easier to correct mistakes and move paragraphs around than writing on a piece of paper.</li>
</ol>
<p>But none of this, in my opinion, captures the full potential of computing. In this use case (the computer as a "third arm"), the user still fundamentally has to perform every action. If the user has 10 files they need to rename, the process of renaming each one is quicker--rather than, e.g. using white-out and hand-writing a new label, the user can just type the new name on the computer. <strong>But crucially, they still have to do the renaming operation 10 times.</strong> If the user had to rename 100 files, they would still have to do the rename operation 100 times. This way of using computers speeds up operations <em>only by a constant factor</em>: what was originally an <code>O(n^2)</code> problem is <em>still</em> an <code>O(n^2)</code> problem.</p>
<p>The thing about coding, or scripting as I will say, is that it gives you the potential for asymptotically better runtimes on your everyday tasks. For example, I have a text file which is a template for a letter, and I want to personalize it for 1000 recipients. This is an <code>O(n)</code> algorithm by hand (e.g. I open it up and write each recipient's name, saving it to the appropriate file), but if I write a script to do it, it's <code>O(1)</code>:</p>
<pre><code>for name in recipients:
with open('template.txt') as templ, open('{}-letter'.format(name)) as f:
for line in templ:
f.write(line.format(name))
# template.txt looks like:
# Dear {}, Thank you for your donation to...
</code></pre>
<p>This goal, of speeding up things we do by more than a constant factor, is why I want to call it "scripting". The goal is not to produce a program, the goal is to <em>use a computer to do something faster.</em> At least for us college kids, opportunities to do this come up in life surprisingly often. Some examples:</p>
<ol>
<li>My girlfriend was required for Chemistry class to make a table of properties (chemical, safety, etc.) of certain given compounds. Normally this involves going to a manufacturer's website (Sigma-Aldrich), downloading a PDF, finding the needed information and writing it down. I helped her write a script to automate the process of downloading the PDF and extracting the information.</li>
<li>A class on ecology planted some flowers in hopes of attracting hummingbirds. They left a camcorder to determine if hummingbirds had actually visited the flowers, but someone had to watch the videos afterward and count the hummingbirds. We're trying to write a script right now to detect hummingbird-like motion automatically, so that only the relevant parts of the videos have to be reviewed.</li>
</ol>
<p>Unfortunately, none of these skills are "sexy", they don't inspire "Ruby on Rails rockstar" attitudes in people. But this sort of pragmatic scripting ability would allow people to actually use their computers to a fuller potential, letting them spend less time mucking about on a computer, and more time living life or doing important things.</p>
Twitter integration2012-05-12T00:00:00-07:00http://nongraphical.com/2012/05/twitter-integration<p><a href="https://github.com/fyhuang/makeblog">makeblog</a> and nongraphical.com now support Twitter integration! Nothing fancy yet, just pulls my latest tweets and slots them in-between blog posts accordingly. (Still working on getting URLs to linkify, hashtags, etc.) One cool feature is the ability to collapse multiple consecutive tweets, using jQuery. This prevents tweets from completely dominating the front page.</p>
Screenshot of Old Site2012-05-10T00:00:00-07:00http://nongraphical.com/2012/05/old-site-screen<p><img class="photo" src="//nongraphical.s3-website-us-east-1.amazonaws.com/2012/old_nongraphical.jpg" /></p>
<p>This is how the site has looked since <a href="/2008/08/the-new-nongraphical-com/">2008</a>.</p>
New Website Design 20122012-05-10T00:00:00-07:00http://nongraphical.com/2012/05/new-website-design-2012<p>As you can tell, I'm in the process of completely redesigning the website! There are still a lot of rough edges--commenting isn't supported yet, old posts look somewhat unpolished, etc.--but be patient and everything will be running smoothly again in a few weeks. The two big changes:</p>
<ol>
<li>New design (lots more whitespace), subject to change</li>
<li>Rewritten backend software (<a href="https://github.com/fyhuang/makeblog">makeblog</a>)</li>
</ol>
<!--more-->
<p>The new backend software? The site used to be run on WordPress, but for this iteration I wrote a static blog generator called <code>makeblog</code>. I've tried to keep the URLs consistent with WordPress-generated ones, so that existing links don't break. The big reason is that my hosting, being shared, doesn't really support PHP accelerators, so WordPress ends up being quite slow. Hopefully this static blog will improve latency overall.</p>
<p>Eventually it will be "mostly" static, transparently supporting commenting. Other soon-to-be-added features:</p>
<ul>
<li>Archives by month</li>
<li>Twitter, YouTube integration</li>
<li>Full site search</li>
</ul>
<p>If this software sounds interesting to you, check out the project <a href="https://github.com/fyhuang/makeblog">on GitHub</a>.</p>
<p><a href="/2012/05/old-site-screen/">This screenshot</a> shows what the old design looked like (from 2008!).</p>
An updated look at social gaming2011-09-17T00:00:00-07:00http://nongraphical.com/2011/09/an-updated-look-at-social-gaming<p>Since I last wrote about "social gaming", my term for gaming as a medium for socialization (as opposed to gaming for the sake of gaming), my opinions on the topic have changed quite a bit. For clarification, I am still talking about <em>video</em> gaming, and my goals are still more or less the same: to use video games as a medium or an excuse, really, to bring people together and create social bonds. Video games are already quite successful at doing this- the aim is to make explicit this desired effect and therefore be able to optimize our gaming activities toward this end.</p>
<p>What social situations actually arise when you invite some friends over to "play some video games"? The most interesting scenario occurs when you have a mix of "hardcore" and "casual" gamers. For me, the striking difference between these groups of people is not gaming ability (although the difference is significant) but rather the attitude that they take toward gaming. As I mentioned above, hardcore gamers play the game primarily to play the game. They are concerned with in-game achievement: getting better scores, more kills, higher APM, that sort of thing. Casual gamers primarily see the game as a focus for socialization. The game itself takes more of a background role.</p>
<p>This causes some problems for socialization, of course. Hardcore gamers are often unaware that their competitiveness makes games un-fun for non-competitive players; in fact, competitive games are almost built to be un-fun for poor players. The majority of fun in Halo or Call of Duty comes from getting kills on other players; if you can't do that, running around and dying every few seconds could hardly be considered to be fun. Additionally, gamers who are too focused on the game won't be able to devote mental time to holding conversations (outside the game) or otherwise socializing with the party.</p>
<p>One possible "remedy" to this "problem" is to encourage people to play co-op games instead of purely competitive ones. (It's worth noting that this isn't so much a social problem as it is my problem. I could sidestep the issue entirely by not using video games as a social medium, but I think it's an interesting opportunity and one worthy of study.) My newest example of a co-op game which encourages socialization is Atom Zombie Smasher, a potentially co-op game about (what else?) killing zombies. Look forward to some analysis and anecdotes about playing this game next time.</p>
DJPlayer, a personal music performance2010-06-09T00:00:00-07:00http://nongraphical.com/2010/06/djplayer-a-personal-music-performance<div class="video"><iframe width="560" height="315" src="http://www.youtube.com/embed/0Af_bi_UDnU" frameborder="0" allowfullscreen="1"></iframe></div>
<p><a href='http://www.youtube.com/watch?v=0Af_bi_UDnU' >DJPlayer Demonstration Video on YouTube</a></p>
<p>This is a project I've been working on for the past quarter for my EE47 class. I didn't want to make just a personal music player, but instead a personal music performance - and this is the more-or-less first prototype of that. It could be described as a "virtual turntable": you load songs into it, and then you can play them back as if they were on a record. You can slow down or speed up the record, or grab it and scratch it.</p>
<p>Read more about the details of the implementation <a href="http://pressplay.pbworks.com/Yifeng+Huang+-+DJPlayer">on the class project page</a>.</p>
Sorting rated items2009-03-24T00:00:00-07:00http://nongraphical.com/2009/03/sorting-rated-items<p>While shopping on Amazon and Newegg, I've come across a most frustrating problem. Both websites offer a sorting feature where you can view items in a particular category usually by price or name or release date or things like that. Both also allow buyers to rate items after they've used them, and allow potential buyers to sort the items based on other customers' reviews. There is a fairly frustrating problem with this system, however.</p>
<p>Both Amazon and Newegg (and presumably thousands of other online stores) sort by <em>average customer rating</em> when told to sort by rating. If I were shopping for, say, computer monitors on Newegg, and I was looking for one that was reliable and rated highly by a lot of people, the average rating system might be misleading. Say there is an HP monitor for sale, which 500 people bought and liked. One person, however, bought it and found a few dead pixels (manufacturing defect - it happens), and so rated it low. The monitor's average rating would be <strong>4.98</strong> out of <strong>5.00</strong> or something like that.</p>
<p>Now consider a no-name monitor that one person bought and liked. He or she is the only person to have ever rated this monitor, and rated it a 5, making the monitor's average rating <strong>5.00</strong>. 5.00 for this no-name monitor is higher than 4.98 for the HP monitor - this would put the no-name monitor <em>higher up</em> on the list if I asked Newegg to sort by "Best rating".</p>
<p>For a selection of two products this seems like a minor problem, but if I were looking for, perhaps, a new DVD burner, the hundreds of products which received two or three 5.00 reviews would fill up many pages of my search with irrelevant products - I would not consider one or two people rating a product a 5.00 to be an accurate indication that the product is, on the whole, reliably constructed. I would have to wade through all those pages before I found the first product rated by more than about five people.</p>
<p>There must be a better way to sort products by customer rating than simply by average rating, which produces misleading results. Newegg's sort by number of ratings is better but still not exactly it. What if five hundred people bought a product and rated it badly? I think a better solution might be some sort of weighted average - 4.98s can be pulled higher than 5.00s if they have more ratings. Something along the lines of (score * number-of-reviews), so that the 500 5.00s that the better product received counts more than the two 5.00s that the inferior product received.</p>
Grace, an original composition2009-02-24T00:00:00-08:00http://nongraphical.com/2009/02/grace-an-original-composition<p>Here is an original composition I wrote, called <em>Grace</em>, for flute, clarinet (in Bb) and piano, based somewhat on the hymn "Amazing Grace". I'm providing it for free, under copyright, but if you decide to perform it, I would appreciate it if you would let me know!</p>
<p><a href='http://nongraphical.com/blog/wp-content/uploads/2009/02/grace.pdf'>Grace (PDF)</a></p>
Problems with the Linux desktop2009-01-02T00:00:00-08:00http://nongraphical.com/2009/01/problems-with-the-linux-desktop<p><em>(Update: in retrospect, I have realized that this article is perhaps not so well written. Expect something more useful and coherent soon!)</em></p>
<p>Linux seems like the perfect solution for the new brand of portable PCs, netbooks. It's efficient, requires few resources, and can run most if not all of the programs one usually runs on such small computers - word processing, email, web browsing, and so on. Large, complex software packages that require Windows to run perform abysmally on low-power computers like netbooks, so effectively the need to run Windows is nullified.</p>
<p>Why, then, do consumers (and reviewers!) choose Windows over Linux for netbooks?</p>
<!--more-->
<p><em>(In the remainder of this article, I will refer to "Linux" when I sometimes mean "the Linux community" and occasionally "the open-source community at large".)</em></p>
<h3>User Interface</h3>
<p>I think the problem is two-fold. First, Linux's user-interface is still not up to par with that of Windows, even Windows XP. GNOME's user-interface has not been truly updated for years, and the basic components of a Linux UI - the file manager (Nautilus), the web browser (Firefox) simply don't run as well as their Windows counterparts. By some trick or sleight of hand, Windows Explorer and Firefox on Windows simply run faster than on Linux. No, it's not measured in raw performance - if anything, web page render rates on Linux should be faster. When the user clicks a button in Windows, or double-clicks a file folder, or anything of the sort, the computer simply responds faster. Especially if the computer is new, computer response time in Windows is almost instant.</p>
<p>This is not true with Linux. Even though Windows tends to slow down far past the level of Linux with time, and Linux more consistently maintains response time, that first impression of the Windows instant response is powerful. I can't put my finger on what causes it right now, but certain options in the Linux kernel config seem to help. On the whole though, the Linux system is tuned more for consistent performance than instantly overridable user response.</p>
<p>This is evident when running multiple, intensive tasks at once. Linux slows down, but everything in the GUI is still clickable. Windows, however, is much less capable at handling complex multitasking. Unfortunately, the ordinary user doesn't care.</p>
<p>Overall, Windows is just more pleasant to use. This is a combination of the above-detailed response time effect, and also because Linux's increased flexibility, also pertaining to the UI, hinders usability. Simply put, the Linux UI needs to be better designed, for <em>ordinary users</em> and not for developers or hackers or power users.</p>
<h3>Economics</h3>
<p>The second problem is one of economics. There are two types of goods in a simple economic analysis - normal goods and inferior goods. Normal goods are those that you buy more of as your income increases. Inferior goods, on the other hand, are goods that you buy only when your income is very low. A common example in economics is single-ply toilet paper - normally, people only buy cheap toilet paper when they have a great need to save money. Wealthier individuals avoid the product altogether.</p>
<p>My proposition is that Linux is currently being seen as an inferior good. <a href="http://blogs.zdnet.com/BTL/?p=11141&tag=nl.e539">This ZDnet blog post</a> explains the situation pertaining to Linux in Africa. Radio stations, an important tool for communication in Africa, prefer to use pirated versions of Windows instead of legally obtained copies of Linux. The Linux distributions proposed are specifically designed for their broadcasting purposes, and in basically all respects have <em>better-designed</em> UIs (for broadcasting) than Windows. In this case, Linux is objectively more suited for their purposes, so why do the radio operators prefer Windows?</p>
<p>According to that post, Windows is seen as a "first world standard", and to the radio stations, encouraging them to use Linux seems like trying to "cheat local people out of getting the same quality of software that is used in the developed world". In this case, Linux is seen as the inferior good. It is seen as the product that one chooses to use <em>only when one does not have the economic resources to use a "better" product</em>, like Windows.</p>
<p>Partly, I blame previous (and in some cases still ongoing) advertising and publicity for Linux as a "low-cost alternative" to Windows. The use of both those terms have created huge problems for Linux's image today. It is seen as being the cheaper "version" of Windows - that which one would buy only if they lacked the ability to pay for Windows. It is also painted as an "alternative", and combined with the efforts (well-placed!) of such projects as wine and OpenOffice.org to ensure Windows compatibility, creates again an impression that Linux is trying to live up to Windows, and should only be used when one has no other choice. Instead of creating choice, Linux seems to have in a way limited it.</p>
<h3>Solutions?</h3>
<p><img src="http://nongraphical.com/blog/wp-content/uploads/2009/01/ubuntulozengestraplogo.png" alt="ubuntulozengestraplogo" title="ubuntulozengestraplogo" width="450" height="138" class="alignnone size-full wp-image-202" /></p>
<p>I honestly don't think very many people, if anyone, has a solution to Linux's persistent image and market penetration problems. I think Ubuntu, my preferred and favorite Linux distro, is the only distribution so far to even come close to a usable, well-respected Linux distribution. (In my opinion, it's more well-respected than usable.) I don't claim to have the answers either. However, I do think that Linux needs to <strong>stop copying Windows</strong>. I don't think that Microsoft's UI is necessarily the best either. OpenOffice.org doesn't have to look <em>exactly</em> like Microsoft Office 2003. More UI innovation from within the open-source community, and also more open-source UI designers, are needed. Linux should be aiming for increased usability, not simply look-alike Windows functionality. UIs for programs need to be designed, reviewed, and tested, with third-party test subjects, if possible.</p>
<p>I do not condone, however, decreased Windows compatibility. Linux needs to work flawlessly with Windows file formats and networks (and, to some extent, Windows applications) in order to be competitive. Development also needs to be easier on Linux. Face it friends, autoconf and automake are outdated and clumsy. Makefiles are outdated. IDEs, such as KDevelop (in all other respects an excellent IDE!), that require the use of autoconf and automake are, by extension, outdated. Software development is too slow and clumsy right now on Linux. This is not to say that Linux-based software development technologies are bad! Subversion, for example, is an excellent version control system. Unfortunately, it's most easily used in conjunction with a Windows-based IDE. Software development needs to be removed from the domain of the text-based editors and command-line hackers, and into the domain of easy, rapid, commercial (and volunteer) development. User-interface development, for example, is extremely easy on Windows due to Microsoft's well-designed tools for UI development. Sure, Qt Designer fills the same shoes, but Microsoft's tools are better-made, and more flexible without sacrificing usability. If Linux could adopt a consistent policy on which UI toolkit to use, and then make that UI toolkit very easy to program with, I'm certain that application development on Linux would blossom.</p>
<p>Obviously the open-source development model has been relatively successful up to this point. Its free flow of information and code encourages iterative development and widens the net for programming talent. Unfortunately, it still has a long way to go. Linux's reputation cannot be fixed by more effective coding alone. The user-interface problems that many Linux programs face cannot be fixed without a more commercial-like development model, or more full-time (maybe paid!) workers. Until that happens, Linux is likely to remain an inferior product in the eyes of the public.</p>
Tuniq Sanctum HDD cooler/silencer2008-12-29T00:00:00-08:00http://nongraphical.com/2008/12/tuniq-sanctum-hdd-cooler-silencer<p><img src="http://nongraphical.com/blog/wp-content/uploads/2008/12/tuniqshot-450x337.jpg" alt="tuniqshot" title="tuniqshot" width="450" height="337" class="alignnone size-medium wp-image-188" /></p>
<p>It doesn't work.</p>
<p>Okay, that's a little bit unfair; it's probably more accurate to say that it doesn't work <em>as expected</em>. The Tuniq Sanctum hard drive enclosure is a 5.25" bay device that holds a 3.5" (or smaller, I suppose) hard drive, and purportedly not only reduces the noise output of the drive but also helps to keep it cool. This device, unfortunately, excels at one aspect of its claimed purpose and fails at the other. While it does indeed keep noise levels down very acceptably, the Tuniq Sanctum enclosure, due to the lack of airflow inside the device, fails to cool the hard drive adequately. In fact, leaving the hard drive inside the enclosure will probably decrease the hard drive's lifetime due to the 60+ degrees Celsius temperatures sometimes experienced inside the device.</p>
<!--more-->
<p><img src="http://nongraphical.com/blog/wp-content/uploads/2008/12/tuniqback-450x337.jpg" alt="tuniqback" title="tuniqback" width="450" height="337" class="alignnone size-medium wp-image-186" /></p>
<p>There are other problems with the Sanctum. Cables passing into the device to connect to the hard drive, as seen here, are obstructed by a piece of foam at the back of the device. The foam puts pressure on the cables, which could be devastating for weaker connectors like SATA cables. The indents you can see above are caused by the wires pushing down on the foam.</p>
<p><img src="http://nongraphical.com/blog/wp-content/uploads/2008/12/tuniqopen-450x337.jpg" alt="tuniqopen" title="tuniqopen" width="450" height="337" class="alignnone size-medium wp-image-187" /></p>
<p>When installing the hard drive into the Sanctum, one is supposed to attach two "thermal pads" to the hard drive. (These pads can be seen in the first photo.) The pads supposedly conduct heat away from the drive to the aluminum fins on the outside. I didn't attach them during my installation, because they would have forced me to continue using the Sanctum with that drive for all eternity - the pads would make the drive thicker than an ordinary 3.5" bay. I don't think the pads can do much to affect the thermals anyway, as foam (no matter how "thermal") can never be a really good heat conductor.</p>
<p>To conclude, the Tuniq Sanctum is probably not worth the money. While it keeps the noise of the hard drive down, its inability to cool the drive adequately makes it basically useless to anyone wanting high performance or longevity from their drive. For new builders, the money spent on this enclosure would be better put toward a quieter or cooler-running hard drive.</p>
Causes of video game piracy2008-12-27T00:00:00-08:00http://nongraphical.com/2008/12/causes-of-video-game-piracy<p><img src="http://nongraphical.com/blog/wp-content/uploads/2008/12/tpb.jpg" alt="" title="tpb" width="275" height="295" class="alignnone size-full wp-image-181" /></p>
<p>There's been a lot of talk recently about why PC gaming is "doomed", mainly because of the ever-growing amount of PC game piracy. I don't necessarily think that PC gaming is doomed at all, although I do think there will be a significant shift in the way the PC game market works - towards a more controlled distribution model, perhaps, like Steam.</p>
<p>This is what I think about piracy, however. It's a self-sustaining cycle, in a way: high video game prices encourage gamers to pirate games instead of buying them, "forcing" video game manufacturers to raise prices or keep prices high in order to not lose revenue. Those high prices in turn continue to encourage piracy. This loop is not necessarily unbreakable, though there are several factors that, in my opinion, contribute to its sustenance:</p>
<!--more-->
<ol>
<li><p><strong>Too much push for realism.</strong> High quality graphics is not necessarily photorealism, but the obsession with photorealism basically ensures that developers and publishers spend enormous amounts of money on game development, and are subsequently extremely afraid of "lost" revenue. This keeps game prices high. I think perhaps a better "marketing catchphrase" would be <strong>believability</strong>. Most games are not realistic at all in any way except for graphics - after all, why play a game if you could do the same thing in real life? Games are, almost by definition, unrealistic. That's what makes them fun. Games do, however, need to be believable. They need to produce suspension of disbelief in the gamer, just like a good movie.</p></li>
<li><p><strong>Anti-consumer policies.</strong> This includes schemes such as DRM and copy protection. It is helpful here to categorize piracy into two groups - "distribution" piracy and "consumption" piracy. Piracy consumers are often somewhat ignorant of their actions - they are simply looking for a cheaper way to play a game. Consumers are not necessarily skilled at manipulating computers or games. Pirate distributors are completely aware of their actions, and are usually the ones who break the encryption schemes on most games. They are usually very computer-saavy.</p>
<p> Which group is targeted by game copy protection schemes? Publishers would like to think the consumers. Copy protection prevents "casual piracy", they say. However, in my opinion the reality is, "casual piracy" occurs when a piracy consumer unknowingly downloads a pirated product from the Internet, that <em>already has the copy protection removed</em>. I'm pretty sure that publishers lose much more money from widespread Internet distribution of pirated games than they do from, say, JoeBob giving his buddies a copy of the game so they can all play together. Copy protection really targets pirate distributors - it supposedly makes it harder for them to distribute games illegally. Does it? Definitely not. Current industry copy protection schemes (Securom, Safedisc, etc.) are easily broken by pirates. "No-CD cracks" for games are released by piraters sometimes even before the game is released. Worst of all, <strong>copy protection schemes convince pirate distributors that the game publishers are evil and greedy and don't deserve the profits from video game sales.</strong> This leads them to continue pirating video games.</p>
<p> What's the lesson here? Copy protection doesn't work, it's easily broken, and all it does is make things worse.</p></li>
</ol>
<p>Some solutions have been proposed to these problems. Centralized content distribution systems, like Steam, propose a seemingly almost-perfect way to control these factors. The built-in "activation" system prevents gamers from installing games that they do not own (as long as those games are Steam-exclusive), giving publishers peace of mind in knowing that their products will have to bring in revenue to be played. However, Steam is installable on as many computers as the user wants, along with its games, so it does not preclude small groups of friends from playing a game together. (Its activation system prevents multiple copies of a game to be played online simultaneously.) The nature of having an account with a username and password makes many people hesitant to freely give away their credentials, making rampant piracy much less appealing.</p>
<p>Its only flaws are this. One is purely technical - Steam does not work through proxy servers, making life extremely difficult for some gamers behind proxies. This can surely be resolved, easily, through some future Steam update. The other is something of a market flaw - Steam only allows games to be purchased new, then kept or gifted. There is no "used games" market on Steam. Some gamers (including myself) buy most games used, which is cheaper and very appealing for those willing to wait for a period after a game's release. eBay prices for many old games are exceedingly affordable. However, because of Steam's lack of a used game market, all game purchases on Steam are at somewhat inflated prices. A game that one could buy on eBay for less than $10 might still sell for $40 on Steam. Gamers who no longer wish to play some game do not have the option to recover some of their expenses in purchasing it - their only option is to give the game away to another Steam user. This means that second-hand transfers of games on Steam is very limited.</p>
<p>I think, with the resolution of these minor issues, platforms like Steam will become the ubiquitous method of distributing games on the PC. Lest developers feel that console distribution is the only way to go, let me put forth my opinion that console gaming is even more anti-consumer: it forces the consumer to buy entirely new, unflexible hardware if some game is exclusive to one particular console. There are currently no such things as cross-console standards. And do not think that console games cannot be pirated. Simple encryption schemes and specialized media do not prevent console games and emulators from being distributed widely on the Internet, as they are even now.</p>
Firefox bookmark shortcuts2008-12-09T00:00:00-08:00http://nongraphical.com/2008/12/firefox-bookmark-shortcuts<p>This is a neat trick I found in Firefox. This works at least in Firefox 3 and may also work in Firefox 2; I do, however, encourage you to upgrade if you're still using Firefox 2, as the third release brings about many needed enhancements in performance and memory usage. Using a bookmark, one can turn the location bar into a sort-of command parser, thereby creating a sort of "keyboard shortcut" for that bookmark. This in effect allows you to create your own custom "keyboard shortcuts" or "location bar commands". Here's an example of how it works. Say I want to create a shortcut for Google Image Search. I can go to the Image Search page, and right click the box, and select "Add a keyword for this search":</p>
<p><img src="http://nongraphical.com/blog/wp-content/uploads/2008/12/quicksearch.png" alt="" title="quicksearch" width="500" height="306" class="alignnone size-full wp-image-176" /></p>
<p>Enter some name for your search; the name doesn't matter. <em>(Alternatively, you could simply create a new bookmark; its target ("location") should be something like <code>http://www.google.com/search?q=%s</code>, where <code>%s</code> represents what will be searched on. Right-click the bookmark you just created and click "properties".)</em> This dialog box will pop up:</p>
<p><img src="http://nongraphical.com/blog/wp-content/uploads/2008/12/quicksearch2.png" alt="" title="quicksearch2" width="377" height="176" class="alignnone size-full wp-image-177" /></p>
<p>In "keyword", type the "command" that you wish to use to access this shortcut. In this case, I would use something like "imgs" or "is". One-letter keywords do not seem to work very well. Once you have entered the keyword and closed the dialog, you can type in the location bar (press CTRL+L to get there quickly):</p>
<pre><code>imgs cute puppies
</code></pre>
<p>Press enter, and behold your search unfolding before your eyes.</p>
Updated Squid 3 configuration2008-11-18T00:00:00-08:00http://nongraphical.com/2008/11/updated-squid-3-configuration<p>Here is the updated version of my <a href="http://nongraphical.com/2008/09/squid-3-proxy-chaining/">previous authenticating/forwarding Squid 3 config</a>. It adds some things and fixes some things. In particular, the peer exclusion rules from the previous config were not working - this one should correctly <em>not use</em> the parent proxies when querying "local addresses". As before, the configuration file contains two proxy servers for load balancing; it can be extended easily to include more.<!--more--> Here it is for your enjoyment:</p>
<pre><code>cache_effective_user proxy
cache_effective_group proxy
http_port 3128
http_access allow all
acl local_ips dst 127.0.0.0/8 192.168.0.0/24 10.10.0.0/16
acl local_servers dstdomain localhost my.local.domain
never_direct allow all
always_direct allow local_ips
always_direct allow local_servers
acl http-only port 80
cache_peer firstProxy.site.com parent 3128 3190 no-query proxy-only login=Username:Password name=prx1
cache_peer secondProxy.site.com parent 3128 3190 no-query proxy-only login=Username:Password default name=prx2
# This makes only HTTP load balanced
cache_peer_access prx1 deny all
cache_peer_access prx1 allow http-only
cache_peer_access prx2 allow all
# Reinforcement of direct rules
cache_peer_access prx1 deny local_ips
cache_peer_access prx1 deny local_servers
cache_peer_access prx2 deny local_ips
cache_peer_access prx2 deny local_servers
# Some timeouts
connect_timeout 8 seconds
peer_connect_timeout 3 seconds
hierarchy_stoplist cgi-bin ?
cache_mem 64 MB
maximum_object_size_in_memory 64 KB
cache_replacement_policy heap GDSF
cache_dir aufs /var/spool/squid3 6000 16 256 # Make sure to check this path
maximum_object_size 16384 KB
access_log /var/log/squid3/access.log squid # Make sure to check this path
shutdown_lifetime 3 seconds
debug_options ALL,1
</code></pre>
Social gaming? Try HoMM 3!2008-11-18T00:00:00-08:00http://nongraphical.com/2008/11/social-gaming-try-homm-3<p><a href="http://nongraphical.com/2008/09/casual-games-for-the-pc/">Last time</a> I wrote about trying to find casual games for medium/large-group social events. We can split multiplayer video gaming into a couple of vaguely-defined categories; I'm going to use the term "casual" or "social gaming" to refer to medium-scale social gatherings that involve video gaming; hardcore gaming, of course, is all about the game; and we might perhaps call the last group "LAN party gaming" to indicate a middle ground between casual gaming and super-intense gaming.</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/no_image.png" class="photo" /></p>
<p>It is for the first category, social gaming, that I suggest a game today: <a href="http://en.wikipedia.org/wiki/Heroes_of_Might_and_Magic_III">Heroes of Might and Magic III</a>.<!--more--> It's kind of an old game - it was released in 1999, but the graphics certainly don't show it. If you look closely (and use the map editor a lot), you'll notice that an incredible amount of time was put into making the artwork for the game. Even at the measly 800x600 or whatever resolution the game uses, the forests and mountains and everything are incredibly detailed.</p>
<p>What is most interesting about the game, however, is its potential for social gaming today. It has two inherent advantages. Old games tend to use disk space much more efficiently (as a necessity), and this one is no exception. The entire installed footprint of HoMM 3 Complete (the original and two expansion packs) is only about 300 MB. I can compress this into an archive and put it on other computers, and get this - HoMM 3 allows you to join multiplayer games without having a CD inserted! You can copy this game to all your friends' computers and have them join your game with exceptional ease. It's second advantage is its turn-based nature: since you cannot do anything when it's not your turn (besides looking around and inspecting your allies' heroes), there is a lot of room in-between turns for conversation and socializing. It's not necessary to be in a frenzied, intense state the entire time one is playing this game.</p>
<p>HoMM 3 games do take a long time to complete (on the order of many, many real-life hours), but multiplayer games can be saved and restarted at any time. Saving is almost instantaneous and basically effortless. I have been trying it out with my friends, and HoMM 3 does indeed make an excellent social game!</p>
<p>Unfortunately, HoMM 3 is no longer published, but you can still buy HoMM 3 Complete (which works, very well, on Vista!) very cheaply at <a href="http://www.mastertronic.com/productPcGamer.asp?pid=331&productLabelID=1">some sites</a>. It might be worthwhile to pick one up soon, especially if you're interesting in social gaming, as I'm not sure you will even still be able to buy this game in a couple of years.</p>
Mouse repairs2008-10-31T00:00:00-07:00http://nongraphical.com/2008/10/mouse-repairs<p><img src="http://blog.nongraphical.com/wp-content/uploads/2008/10/pa312365-small.jpg" alt="" title="pa312365-small" /></p>
<p>This is a mouse that was once broken but is now healed. (A mechanical switch on the circuit board was broken; upon fixing that, the mouse works almost like-new.) I was actually quite surprised at the extreme simplicity of the actual mouse hardware - a couple of resistors, capacitors, an LED for the sensor, and the sensor chip itself. It seems to me that the costs for building such a mouse must be rather cheap indeed. In fact, I wonder now about the optical trackballs out on the market today - mine (the <a href="http://blog.nongraphical.com/2008/08/kensington-expert-mouse-70/">Kensington Expert Mouse</a>) is to all appearances just an upside-down optical mouse with a ball and a couple of extra buttons; would it be perhaps possible to construct my own perfectly-functioning trackball with only cheap optical mouse parts?</p>
<!--more-->
<p>Fascinating as that may seem, there are indeed <a href="http://ssandler.wordpress.com/MTmini/">more exciting projects</a> to attend to first.</p>
Disable virus scanning in Firefox after download2008-10-02T00:00:00-07:00http://nongraphical.com/2008/10/disable-virus-scanning-in-firefox-after-download<p>Here's how to stop Firefox from automatically virus scanning all downloads after they've finished - something that's been annoying me since I've upgraded to Firefox 3 because of the extraneous disk accesses it creates. Open up the <code>about:config</code> (open a new tab, type <code>about:config</code> in the location bar), and find the <strong><code>browser.download.manager.scanWhenDone</code></strong> value. Type in <code>browser</code> in the filter bar for quick searching. Set that value to false by double-clicking. And that's it! What, were you expecting something more?</p>
<p>(originally read <a href="http://www.ghacks.net/2008/06/04/disable-automatic-virus-scanning-in-firefox-3/">here</a>)</p>
A tool for removing duplicate files2008-10-02T00:00:00-07:00http://nongraphical.com/2008/10/a-tool-for-removing-duplicate-files<p><a href="http://nongraphical.com/media/uploads/RemoveDuplicates.py">Download RemoveDuplicates.py</a></p>
<p>One of the problems with using hybrid Windows and Linux environments is that one needs to watch closely for filesystem and file anomalies and inconsistencies. Differing end-of-line markers, for example, cause many problems when sharing files between the two operating systems. One particular problem I've run into is that of having duplicate files, or in other words, multiple files with the same filename. This can happen if, say, you copy a directory somewhere in Windows, then switch to Linux and use a tool such as rsync to copy that same directory over again. If the capitalization is different, Linux will not replace the old files, because Linux, unlike Windows, is case-sensitive. This will even happen, and is technically acceptable, on NTFS filesystems.</p>
<p>The solution I've come up with is this simple script, called RemoveDuplicates.py. Obviously, you need <a href="http://www.python.org/">Python</a> installed to run it, but it has no additional dependencies. Simply run it <em>in the directory you wish to clean</em>, and it should do the rest. Note that you shouldn't use this for entire filesystems (yet), because it will use ridiculous amounts of memory if it is given a high number of files. <a href="http://nongraphical.com/media/uploads/RemoveDuplicates.py">Download it here</a>!</p>
<p>P.S. Also, I cannot guarantee that this tool will work as intended or will be bug-free. Use wisely.</p>
Bad marketing gimmicks2008-09-30T00:00:00-07:00http://nongraphical.com/2008/09/bad-marketing-gimmicks<p>Some of the stuff that Logitech has been putting out recently is certifiably gimmicky. For example, the <em>wireless</em> trackball mice (<a href="http://www.logitech.com/index.cfm/mice_pointers/trackballs/devices/189&cl=us,en">Cordless Trackman Optical</a>) that Logitech makes. The whole point of a trackball is that it <em>stays put</em> on your desk: only the ball moves! Why, then, is it made wireless? Wireless mice are cool because the cord doesn't get in the way when it moves along with the mouse, but the trackball base doesn't move! Logitech's site even calls the wireless feature "convenient" - I personally don't think that needing to change batteries for a feature that the device doesn't require is convenient.</p>
<p>One more seemingly-useless Logitech feature: the G15 keyboard's LCD. Gamers that would buy the G15 keyboard - most likely MMO players and, to a lesser extent, FPS players. The G15's most outstanding feature is its plethora of assignable macro keys, which makes it wonderful for, say, WoW. Why, though, would you look down from the game on your monitor to check some dimly-lit stats on your keyboard LCD? Seems pointless to me.</p>
<p>Don't get me wrong: Logitech is a wonderful peripheral company. They make what I consider to be the world's best general-purpose mice (Dell's basic USB mouse included with their desktops, my personal favorite, was<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> made by Logitech). They make relatively good, usable keyboards, sometimes with a touch of my preferred minimalistic style (DiNovo Edge). And, despite arguments between Logitech, Razer, and now Microsoft users about which gaming mouse is the <em>best</em>, there's no doubt that Logitech's, especially the G5, are among the top gaming mice available. It's just that nobody really wants to spend extra money buying features that are completely unnecessary.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>I’m not entirely sure that it is anymore; I don’t have this information.<a href="#fnref:1" rev="footnote">↩</a></p></li>
</ol>
</div>
Casual games for the PC?2008-09-27T00:00:00-07:00http://nongraphical.com/2008/09/casual-games-for-the-pc<p>My current question is this: why are there few (if any!) casual/party multiplayer games for the PC? I've been looking around for games that might appeal to more than just me and my hardcore gaming friends, in a (perhaps vain) attempt to create social gatherings through video games/LAN parties. Because everyone here at school has a computer, and networking is already very-well taken care of, it's definitely very plausible. The only things missing now are the games.</p>
<!--more-->
<p>Currently, I play a fair amount of Call of Duty, which is an excellent PC FPS. I prefer it over other multiplayer PC shooters simply because I think CoD's gun firing sounds and animations are much more gratifying. Okay, that's a little exaggerated: Call of Duty is an incredible, polished game with many very good elements. Its multiplayer is excellent when you're playing on computers that already have the game installed, and with people that have played shooters before. With both these components lacking, however, Call of Duty is not a particularly effective multiplayer experience.</p>
<p>I'm currently looking for games that are easy to pick up, can be played in a very short amount of time, and have fairly small installation footprints (or better yet, can be played from a CD or the network). Those qualities, in my opinion, will make a game that is much more accessible than today's games, and will turn video gaming into a much more inclusive and ultimately more socially successful activity.</p>
<p><a href="http://www.rndlabs.ca/bv2/">Babo Violent 2</a> comes close. It's small and very, very simple for a shooter. Obviously it doesn't work with people who don't enjoy shooting other people, but it's about as close to a "party game" as I can think of for the PC. Game consoles have it better in this respect: Mario Party, for example, or DDR, or Guitar Hero (although those games have acquired something of a hardcore cult status as well) are good examples. I suppose I'll just have to wait patiently here for casual PC gaming to catch up and provide us with more accessible party games.</p>
VMware & Ubuntu 8.042008-09-25T00:00:00-07:00http://nongraphical.com/2008/09/vmware-and-ubuntu-8-04<p>I have been having, to put it lightly, some problems with VMware server and an Ubuntu guest. My guess as to why is this: VMware server is, in my eyes, built for production-level server virtualization. It's not really built for on-the-side home server virtualization, like the kind that I'm doing, and on fairly desktop-oriented hardware to boot. Basically, my Ubuntu install often has trouble with disk access, and sometimes network access as well. (I'm running a Vista Home Premium host with an Ubuntu Server 8.04 guest.)</p>
<!--more-->
<p>My disk access problems probably stem from the fact that my VMware disk and my system boot disk are both the same partition and the same disk. This probably causes all sorts of access issues, especially while my computer is booting (I have noticed that my computer takes forever to stop thrashing the disk after logging in). The network problems are more evasive, however. I'm using the NAT networking interface so that I can assign my Ubuntu a static IP address that will never change, even if my physical computer changes location (and it will, often). However, pretty frequently the DNS "server" that VMware provides breaks down, and while Ubuntu is able to send packets to the network, it cannot perform DNS queries through the local DNS service. Occasionally, the network will fail to operate altogether, and Ubuntu will be unable to send any packets anywhere (including to the host computer!). This is a problem which I've looked for solutions for online, but have so far come up with nothing.</p>
<p>Finally, I would like to be able to serve files from the host computer through a web server on Ubuntu, and my current method of mounting the host shares with CIFS and then sharing them with Apache is not optimal (the least of the problems with this method is redundant network usage). I would like to get the VMware shared folders feature working, except that I cannot seem to compile the VMware tools' kernel modules on Ubuntu 8.04 (even following other references online). VMware's kernel module builder is not quite as polished, evidently, as others' (like nVidia).</p>
<p>Hopefully I will find solutions to these problems soon, as I really like the idea of running a virtualized Linux server on a Windows host, and hope that this sort of arrangement will prove fruitful.</p>
Programming Club!2008-09-25T00:00:00-07:00http://nongraphical.com/2008/09/programming-club<p>Hello, fellow programmers! I'll be posting useful information, practice, tutorials, resources, and all other things vaguely programming-related here. Soon there will be posted a general outline of what's going to be happening this year, but for now, just let me say that we'll be working mainly with web applications and web development. It should be pretty apparent from reading recent technology news that the IT world is focused on two main trends right now: web apps and the eventual "web desktop," and of course server virtualization. Suffice it to say that, after you're through with this year's programming club, you should have a very workable basic understanding of how the Internet works and how to write applications that are web-accessible.</p>
<p>So with that said, our concrete goal for the moment is to become relatively fluent in HTML and CSS. We won't learn too much, just enough to understand how it all works and how to make it work for us. These two languages will enable us to create decent-looking web pages and will also provide the presentation layer of our later web development work.</p>
<p>Stay tuned for more information. I find this all rather exciting, and I hope you guys do too!</p>
Squid 3 authenticating proxy chaining2008-09-13T00:00:00-07:00http://nongraphical.com/2008/09/squid-3-authenticating-proxy-chaining<p>My school uses an NTLM-authenticating proxy server, and this causes problems with lots of applications which don't support proxy servers. Many, many solutions have been proposed to this problem, but I'll focus on one that I find particularly appealing: setting up a non-authenticating personal proxy server which forwards requests to the main proxy server.</p>
<p><strong>Update: use the <a href="http://nongraphical.com/2008/11/updated-squid-3-configuration/">new version of this config file</a> - it works better.</strong></p>
<!--more-->
<p>Here's why this solution is optimal, or at least better than other currently-available solutions. Consider one method of forcing programs to use the proxy (under Linux), which is setting the http_proxy and ftp_proxy environment variables. Programs that <em>support</em> proxy servers <strong>and</strong> that support proxy <em>authentication</em> (because my school uses an authenticating proxy), notably apt-get, wget, and lynx, will use those environment variables to connect through the proxy server. Programs that don't, or those that don't read the environment variables (biggest offenders: most GNOME programs), won't.</p>
<p>The biggest problem with this method is its inconsistency - it's impossible to know necessarily which programs work, and which programs support proxy authentication; and in addition, one needs to re-enter one's proxy settings in the environment variables (bashrc, probably), in the GNOME settings, and probably individually for some programs too. On top of that, many GNOME programs don't (or didn't) support proxy authentication... finally, it is impossible in the environment variable to specify which connections (like those to the local network) should be direct, and which should be through the proxy.</p>
<p>Consider a slightly better method, which is <code>proxychains</code>. In order to use proxychains, one must type commands like so:</p>
<pre><code># Instead of writing
sudo apt-get install ubuntu-desktop
# One must write
sudo proxychains apt-get install ubuntu-desktop
</code></pre>
<p>Okay, so that's not too bad, if a little bit inconvenient. The good thing about this method is that proxychains can "proxify" programs that don't support proxy servers natively. The proxy authentication username and password are also stored in one place only: the proxychains configuration file. The only two problems with this method? 1. Typing <code>proxychains</code> before every command, and 2. The inability of <code>proxychains</code> (at least the most recent version) to make some connections direct (i.e. those on the local network) and some to go through the proxy, just like the previous method.</p>
<p>Fine, so those methods aren't ideal. What makes the Squid 3 method better? Well, on the surface it solves most, if not all, the problems that the previous methods had. It doesn't require authentication (that is handled transparently by the personal proxy) and authentication information is stored in one place only (the squid.conf). This alone makes many programs work much better. You can cache far more personalized web data (the school's proxy serving hundreds of students probably won't cache data that <em>you, personally</em> frequently use), and saving proxy information in many different places is okay, because if your username and password change, you don't need to change it in all those different places. Finally, one can still use proxychains to proxify misbehaving programs, because Squid can be configured to connect to some addresses directly instead of proxying through the parent proxy. Its biggest problem is that running Squid more or less requires Linux.</p>
<p>Okay, enough banter. Let's learn how to do this thing. I'm using Ubuntu 8.04 server (on a virtual machine), so these instructions may or may not be Ubuntu-specific. Here's my config file:</p>
<pre><code>cache_effective_user proxy # Ubuntu-specific?
cache_effective_group proxy # Ubuntu-specific?
http_port 3128
http_access allow all
cache_peer prx1 parent 3128 3190 no-query login=username:pass
cache_peer prx2 parent 3128 3190 no-query login=username:pass
cache_peer_access prx1 allow all
cache_peer_access prx2 allow all
hierarchy_stoplist cgi-bin ?
cache_mem 64 MB # How much memory Squid uses for cache.
# Make lower if you have less memory
maximum_object_size_in_memory 64 KB # Make lower if you have less memory
cache_replacement_policy heap LFUDA
cache_dir aufs /var/spool/squid3 6000 16 256
maximum_object_size 16384 KB
access_log /var/log/squid3/access.log squid
shutdown_lifetime 1 second
acl local-servers dst 127.0.0.1 192.168.1.0/24
never_direct deny local-servers
never_direct allow all
</code></pre>
<p>There are two "parent" proxies in this file which this personal proxy can access. Obviously, replace <code>username</code> and <code>password</code> with your own authentication information. Also, don't forget to change <code>cache_effective_user</code> and <code>cache_effective_group</code> to your liking or your distro. Change the <code>cache_replacement_policy</code> to fit your caching needs, and finally, make sure to edit the <code>acl local-servers</code> to specify which servers you do not want to proxy.</p>
<p>After doing this, you should be able to restart Squid and have everything working! Next up: transparent proxying with iptables.</p>
Call of Duty 2 problems on Windows Vista 32-bit2008-09-05T00:00:00-07:00http://nongraphical.com/2008/09/call-of-duty-2-problems-on-windows-vista-32-bit<p>I found today that I was having problems launching Call of Duty 2 on Windows Vista. I could not start either the single or multiplayer: both would crash and the Vista "this program has stopped working" dialog box would pop up. A quick search on the Internets told me that this was definitely a common problem, and with the help of some pretty obscure forum posts, I finally figured it out. I'm going to summarize my solution here for future reference:</p>
<p><strong>System environment:</strong></p>
<ul>
<li>nVidia graphics card</li>
<li>Windows Vista Home Premium 32-bit</li>
<li>2 GB RAM</li>
<li>Integrated "HD" audio</li>
</ul>
<p><strong>The solution for me:</strong></p>
<ol>
<li><strong>Remember to set CoD2 to compatibility mode with Windows XP SP2!</strong> You can do this by right-clicking the shortcut and selecting "Properties", then opening the "Compatibility" tab at the top.</li>
<li>First tried updating DirectX 9. Vista users should note that DirectX 9 and DirectX 10, while both coming pre-installed on Vista, are <em>separate components</em>. You should still update to the latest DirectX 9 even if you have DirectX 10. Unfortunately, while a good first step, this didn't work for me.</li>
<li>Then, added "+set com_introplayed 1" to the end of the shortcuts. You can do this by opening the shortcut properties (see step 0) and adding those characters, without quotes, to the end of the "Target:" box, so that the full line looks like:
"C:\Program Files\Activision\Call of Duty 2\cod2sp_s.exe" +set com_introplayed 1
This fixed the single-player for me, but I still could not open multiplayer.</li>
<li>I found on <a href="http://www.ntcompatible.com/Call_Of_Duty_2_c12762.html">NTcompatible.com</a> a seemingly-ridiculous little proposition. The poster suggested that, to run CoD2 multiplayer, one should <strong>plug something in to the microphone jack</strong>. So, I did, and lo and behold, it worked! Rather a strange solution, I do say. It likely has something to do with the interaction between my integrated audio and the voice chat features of CoD2, so turning off voice chat might allow it to run without a microphone plugged in.</li>
</ol>
<p>Anyways, that's how <em>I</em> got this game to work on Vista; hope it helps somebody else too!</p>
Personal build - ultra-silent, uATX, gaming - part 22008-09-02T00:00:00-07:00http://nongraphical.com/2008/09/personal-build-ultra-silent-uatx-gaming-part-2<p>I finally received my new motherboard and installed it into my computer. It runs quite well, quite cool, and very quiet. Here's the final details on the quiet cooling system:</p>
<p><strong>Fans/airflow:</strong></p>
<ul>
<li>2 x quiet 60mm fans behind the CPU cooler</li>
<li>1 x SilenX 60mm fan next to video card, doubles as case exhaust</li>
<li>1 x 120mm fan in PSU, helps move air through CPU cooler</li>
<li>1 x Arctic Cooling 90mm PWM fan on other side of CPU cooler</li>
</ul>
<p><strong>Heatsinks:</strong></p>
<ul>
<li>Thermaltake Big Typhoon (modified) on CPU (removed fan and fan mount)</li>
<li>Arctic Cooling Accelero S2 on video card</li>
<li>Tuniq Sanctum hard drive silencer/cooler</li>
</ul>
<p>Effectiveness? CPU temperatures at 37-40 degrees C at idle. Not too shabby, I suppose. I'm planning to use (and already using) this machine for some serious computer work, including 3D programming and graphics. I've actually recently installed Visual C# 2008 Express Edition, and I'm finding C# (and Microsoft's IDE) to be an incredibly powerful and intuitive language. I think I might switch to using C# indefinitely, until someone writes a decently simple and powerful IDE for <a href="http://www.digitalmars.com/d/">D</a>, my cross-platform language of choice. Oh, and fix X11 and give us <em>one</em> windowing toolkit that works and has amazing graphical tools while you're at it, please?</p>
<p>I'm also running VMware server (and having lots of problems with that...) with an Ubuntu 8.04 Server guest, to handle my requisite Apache and MySQL stuff, and also to keep up with the very few Linux-only softwares I use.</p>
Google Chrome - first impressions2008-09-02T00:00:00-07:00http://nongraphical.com/2008/09/google-chrome-first-impressions<p>So here it is, finally: the legendary <a href="http://www.google.com/chrome">Google browser</a>.</p>
<p>And like everything else that Google puts out, it is a gloriously incredible piece of work. It has the best characteristics a piece of software could have: it's simple, fast, responsive, and stable. I've been running it for just a little while now, and while WebKit's rendering (especially of fonts) is slightly different from Gecko's, everything works just about the same as in Firefox... it's all just way, way faster. Opening new tabs is faster. Using Gmail is faster (thanks, no doubt, to the new V8 JavaScript engine). Writing posts is faster. It's really quite incredible... in fact, possibly one of the most impressive open-source developments to date, right up there with Firefox 1 and the Linux kernel. <a href="http://www.google.com/chrome">Give it a spin yourself and see</a>.</p>
DDvorak, a programmer's keyboard layout2008-08-26T00:00:00-07:00http://nongraphical.com/2008/08/ddvorak-a-programmer-s-keyboard-layout<p>Something I discovered today: <a href="http://www.siteuri.ro/dvorak/DDvorak.aspx">DDvorak</a>, a keyboard layout loosely based on Dvorak which caters specifically to developers or programmers. There's a <a href="http://www.siteuri.ro/dvorak/">layout tester</a> on the same site that measures the overall efficiency of various typing layouts with any text that you choose.</p>
<p>DDvorak, on first glance, is a completely unorthodox typing layout. It requires comma as a dead key for many symbols, and AltGr as a modifier for many others. Additionally, many things are moved to unconventional locations (BackSpace is where 'B' is on QWERTY keyboards, for example). However, the <a href="http://www.siteuri.ro/dvorak/">layout tester</a> consistently measures the efficiency of DDvorak as significantly higher than either Dvorak or <a href="http://colemak.com/">Colemak</a>, no matter whether typing English or code.</p>
<p>I think I'm going to have to give DDvorak a try, soon, if only I could figure out how to radically change keyboard layouts in X.org... of course, it's easy with <a href="http://www.microsoft.com/globaldev/tools/msklc.mspx">Windows</a>. It wouldn't be Windows if there weren't a tool for everything.</p>
Personal build - ultra-silent, uATX, gaming - part 12008-08-25T00:00:00-07:00http://nongraphical.com/2008/08/personal-build-ultra-silent-uatx-gaming-part-1<p>What you see here is a computer I just built for myself, which was to be quiet as possible, while still keeping the thermal performance under control. All of this, of course, in a machine with more-than-adequate performance for gaming, 3D rendering, Photoshop work, and video encoding. Here's a photo of the final build:</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/no_image.png" alt="uATX silent gaming build" title="uATX silent gaming build" width="300" height="225" class="size-medium wp-image-54" /></p>
<p>I used a Thermaltake Lanbox Lite case to house this computer. The major components I selected for this build were an Intel Core 2 Quad, 2 GB of RAM, and an nVidia 9600 GT video card. The 9600 GT is cooled almost-passively with an Arctic Cooling Accelero S2 cooler, and the CPU is cooled almost-passively with a Thermaltake Big Typhoon. Air exhausts from the system with one low-speed 60mm fan behind the CPU and one low-speed 60mm fan beside the video card. A 90mm PWM fan pushes air through the CPU cooler. The thing you see in the top 5.25" slot is a Tuniq hard drive silencer: it surrounds the hard drive with sound-blocking but thermally conductive foam.</p>
<p>Unfortunately, due to a stupid mistake I made, I need to replace the motherboard I originally purchased, so I can run the system right now... when my new one arrives hopefully I'll post some screenshots and benchmarks.</p>
Blizzard Rox.2008-08-25T00:00:00-07:00http://nongraphical.com/2008/08/blizzard-rox<p>I just found out about (old news) the Starcraft 1.15.2 patch, otherwise known as the "officially-sponsored no-CD patch". I wish more game companies would follow this example and realize that copy protection is useless: no matter how advanced, gamers figure out ways to avoid copy protection, and it just causes problems for innocent and legitimate users anyway.</p>
<p>On the other side of the coin, more gamers should just grow up and realize that companies <em>do</em> want to get paid for making games, and that they should think about maybe paying for their games every once in a while. Take the advice found in no-CD crack READMEs to heart: if you like this game, please consider purchasing it. If both sides of the "battle" work together, we can maybe end this ridiculous anti-consumer nonsense.</p>
<p>Still, it would be nice if more game companies would patch their games like this. Preferably a little sooner after their game is released too!</p>
Lightweight Linux on Old Laptop, part 1: Xubuntu2008-08-20T00:00:00-07:00http://nongraphical.com/2008/08/lightweight-linux-on-old-laptop-part-1-xubuntu<p>I recently acquired a really old, Celeron-class laptop with something like 128 MB of RAM and a 10 GB hard drive. It came with Windows ME, but I wanted to install some form of Linux on it and make it at least marginally useful, as sort of a lightweight family PC. I have but few goals for this machine: it should be able to surf the web (no Flash necessary; would even sacrifice JavaScript), it should be able to process Word documents, and if at all possible it should be able to run some older Windows apps using <a href="http://www.winehq.org/">Wine</a>.</p>
<p>My first attempt at creating such a thing came with Xubuntu 8.04. At first I tried to use the bundled Firefox 3 and Xfce desktop environment... but as it turned out, that was too much for the slow hard drive and processor of my old computer. I decided to replace Xfce with <a href="http://www.icewm.org/">IceWM</a>, an old favorite of mine. Similarly, I replaced Firefox 3 with <a href="http://www.twotoasts.de/index.php?/pages/midori_summary.html">Midori</a>, a much lighter-weight web browser based on WebKit. I kept the Xfce terminal emulator though, because I much prefer it to <code>xterm</code> and don't want to install <code>gnome-terminal</code>. I also installed <a href="http://idesk.sourceforge.net/wiki/index.php/Main_Page">iDesk</a> to provide some primitive desktop icons.</p>
<!--more-->
<p>Here's a screenshot of my awesome new Linux desktop in action:</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/no_image.png" alt="Screenshot of IceWM with iDesk, xfce4-terminal, and the GIMP" title="IceWM screenshot" width="300" height="225" class="size-medium wp-image-47" /></p>
<p>It is rather primitive, as you can see. Note the, uh, shamelessly ripped-off titlebar graphics. One problem remains, however: the computer takes far, far too long to boot up. It seems to me that, despite Xubuntu being relatively stripped-down compared to regular Ubuntu, it's still too bloated for my old computer. That is why this is only "part 1": my next plan is to see if I can build a super-lightweight Gentoo-based system for my old laptop, hopefully with something like software suspend (now <a href="http://www.tuxonice.net/">TuxOnIce</a>) to improve response times. At the same time, I might take a leaf from gOS (1.0)'s book and use the Enlightenment window manager.</p>
Beware Gigabyte's @BIOS!2008-08-18T00:00:00-07:00http://nongraphical.com/2008/08/beware-gigabyte-s-bios<p>Bundled with Gigabyte motherboards is a small utility called "<code>@BIOS</code>", which purports to have the ability to update the motherboard BIOS from within Windows, XP or Vista. A lot of "advanced" computer users tend to be wary of such a proposition, but Toshiba laptop BIOSes actually do have this functionality and it works quite well.</p>
<p>Unfortunately, Gigabyte's tool does <em>not</em> work as expected. I tried to update my BIOS from within Windows Vista, with <em>no other programs running</em>, and <strong>the program crashed</strong> in the middle of flashing the ROM. Fortunately, I expected that my board would be dead, so I looked some stuff up on Google before I rebooted. Posts on some forums told me that the BIOS would auto-recover an image from the hard drive, so I downloaded Gigabyte's latest BIOS from their website and put it on the root of my drive. I was lucky; when I rebooted, the BIOS found the image and was able to recover itself.</p>
<p>Lesson learned? Avoid @BIOS like the plague.</p>
Instant Indexing on Google2008-08-16T00:00:00-07:00http://nongraphical.com/2008/08/instant-indexing-on-google<p>Today I had a problem with <a href="http://free.grisoft.com/">AVG free anti-virus</a> (my favorite free anti-virus software, by the way). The updater component told me that "<code>a .bin file is missing</code>", a problem which I could not solve myself. So I searched on Google for it, and lo! the top entry is a <a href="http://www.neoseeker.com/forums/62/t1216894-avg-free-8-bin-file-missing/">forum post</a> explaining that it's just a temporary problem with AVG's updates and should be fixed tomorrow...</p>
<p>Wait a second, a temporary problem that should be fixed tomorrow? I checked the date on the post, and it was from today. I knew that Google had a lot of distributed computing resources... but being able to find and index posts, giving them reasonable PageRanks on the <em>day that they appear</em>?</p>
<p>I have now developed an entirely new respect for the power of Google.</p>
crarchive 0.12008-08-13T00:00:00-07:00http://nongraphical.com/2008/08/crarchive-0-1<p><a href="http://nongraphical.com/media/uploads/crarchive-0.1.tar.gz">Download <code>crarchive</code> version 0.1.</a></p>
<p>Here's a little program I wrote to solve a small problem I've been having with cron. Say one has in one's crontab the following line:</p>
<pre><code>0 0 * * * /usr/bin/rsync -avz dir1/ /backup/dir1/
</code></pre>
<p>This backs up <code>dir1</code> to a backup directory. <code>rsync</code>, however, creates a lot of output (especially with the <code>-v</code> switch)... and cron sends that output to your email, so every day, you'll be getting an email message from cron with the results of the backup. To avoid this, most people simply redirect the output to <code>/dev/null</code>. What if I do actually want to see the output though, just not in my inbox?</p>
<!--more-->
<p><code>crarchive</code> is a little script that will log the results of cron runs in a folder, gzip old logs, and delete really old logs automatically. It allows the output of commands run in cron to be saved and archived, but without clogging up your inbox. Eventually, it will also support more customizability, but because this is only the first release, it has the following limitations...</p>
<ul>
<li>Maximum one run per day</li>
<li>Logs to <code>$HOME/logs</code> (unchangeable)</li>
<li>Gzips logs that are one day old, deletes logs that are thirty (unchangeable)</li>
</ul>
<p><code>crarchive</code> <em>will</em>, however, email you if something goes wrong (unfortunately, again, error checking in this early version is primitive). Here's a usage example with the crontab from earlier (assuming we've installed <code>crarchive.py</code> into <code>/usr/bin</code>):</p>
<pre><code>0 0 * * * /usr/bin/rsync -avz dir1/ /backup/dir1/ | /usr/bin/crarchive.py rsync-dir1
</code></pre>
<p>Where <em><code>rsync-dir1</code></em> is an arbitrary name that you choose.</p>
<p>I'm currently using <code>crarchive</code> to log an <a href="http://awstats.sourceforge.net/">awstats</a> update that I'm running in my crontab. If you think that <code>crarchive</code> would be of some use to you, <a href="http://nongraphical.com/media/uploads/crarchive-0.1.tar.gz">download version 0.1</a>.</p>
The New Nongraphical.com2008-08-11T00:00:00-07:00http://nongraphical.com/2008/08/the-new-nongraphical-com<p>Welcome to the new Nongraphical.com! Obviously, I've made a lot of changes here. It's a whole new design with a whole new backend. I suppose I should say that it's also a whole new blog. I'll be writing reviews, mostly on what I consider useful tech. I'll also be publishing articles and tutorials on topics I can't find elsewhere.</p>
<p>And hey, if you like this, let me design something like it for you! I do styles, PHP and Python programming, and also work with third-party apps (like <a href="http://wordpress.org/">WordPress</a>). I also try for 100% valid XHTML and CSS. Check out my portfolio for more information.</p>
Kensington Expert Mouse 7.02008-08-11T00:00:00-07:00http://nongraphical.com/2008/08/kensington-expert-mouse-7-0<p>I decided to write this review to share my own experience of buying a trackball mouse: I had been comparing between what are basically the two most full-featured trackballs on the market today, the Logitech Cordless Optical TrackMan and the Kensington Expert Mouse 7.0. Unfortunately, trackballs are not very popular among computer users today, and so I had a very hard time finding an Expert Mouse to try out for my own. In the end, one of my friends owned the Logitech trackball and a different (non-optical) Kensington trackball product, and I ended up buying the Expert Mouse. To sum up this entire review, <strong><a href="#concl">I am extremely happy with my purchase</a></strong>; read on for my reasons.</p>
<p><img src="//nongraphical.s3-website-us-east-1.amazonaws.com/no_image.png" alt="Kensington Expert Mouse 7.0" title="Expert Mouse 7.0" width="300" height="225" class="photo" /></p>
<!--more-->
<h3>Why a Trackball? ### {#why}</h3>
<p>I've been using a trackball (first my friend's Kensington, and now my own) for over a year now, and I've found two very good reasons to use a trackball over a normal mouse:</p>
<ol>
<li>First, it is possible using a trackball, unlike with normal mice, to click without any chance of moving the cursor. This is extremely useful for precision work.</li>
<li>Secondly, trackballs do not take up very much desk room, and eliminate the picking-up and re-centering that is very common with normal mice.</li>
</ol>
<p>It may be argued that trackballs reduce wrist stress compared to normal mice, and my subjective evaluation confirms that, although YMMV of course. It may also be argued that trackballs offer increased precision over normal mice; I've also found this to be generally true, as the ball is generally quite heavy and can be nudged precisely with little effort.</p>
<h3>Tracking and Features ### {#tracking}</h3>
<p>The non-Expert Mouse Kensington I used for a while was based on a mechanical tracking mechanism, in a manner similar to that of a normal ball mouse (who uses a ball mouse these days?). The tracking on that Kensington was excellent: it was precise, fast, and accurate, and never really gave me any troubles. Of course, being mechanical, it required frequent cleaning. Mouse manufacturers saw this problem in ball mice, and optical mice became quickly popular. Trackball makers have been slower to catch on though, and so while mice have moved on even to laser tracking mechanisms, many trackballs sold are still mechanical.</p>
<p>Both the Logitech Optical TrackMan and the Expert Mouse have optical tracking mechanisms, but their implementation is quite different. The Logitech has an infrared sensor of some sort: it emits no visible light, and so arguably is less visible in dark rooms (say, college dorm rooms at night). The Expert Mouse functions just like an upside-down optical mouse, using a red LED. One may argue the various fine points of the two implementations (like visibility at night), but by my personal subjective judgment, the Expert Mouse tracking is far superior. When I move the ball in a "straight line" using the Logitech mouse, the cursor doesn't follow that motion: it <em>tries</em> to move in a straight line, but sometimes travels diagonally and is generally quite inaccurate. There is also a slight but noticeable amount of lag present using the Logitech trackball. Obviously this is a disappointment from a $50 trackball from a peripheral company that makes some of the world's best input devices.</p>
<p>Some other reviews indicate that the Expert Mouse is not entirely accurate in tracking; however, I have found that the Expert Mouse tracks extremely well: just as well as the older mechanical Kensington.</p>
<p>There are some who measure the effectiveness of a mouse by the number of buttons it has... I suppose it's somewhat important in some cases, but in my opinion not here. I wanted to upgrade from my friend's older Kensington because it lacked a middle button, and a scroll wheel, therefore making my computing life very difficult. Both the Expert Mouse and the Optical TrackMan have both these features, although the Expert Mouse's button layout is similar to that of other Kensington trackballs (and the Logitech Marble), while the Optical TrackMan's is quite unusual. Personally, I find the Expert Mouse's to be more natural (the lower-left and lower-right buttons are the left- and right-click), but you may prefer the Logitech's. I only use three of the four buttons provided with my Expert Mouse.</p>
<p>The Expert Mouse's scroll wheel (or scroll ring, as they call it) is an iPod-like physical ring around the trackball, and the TrackMan's is just like the scroll wheel on a normal mouse. The TrackMan is cordless, but since the trackball doesn't move on your desk, I can think of no legitimate reason why one would need a cordless trackball. It's obviously just a marketing gimmick.</p>
<h3>Gaming ### {#gaming}</h3>
<p>So we've established that the Expert Mouse is a wonderful tool for everyday mousing. Let us then explore the other side of mousing, then: gaming. I'm admittedly still a fan of using a traditional mouse for gaming, but that doesn't mean it's impossible to play games with a trackball. Strategy or point-and-click RPGs work especially well with my trackball, and FPSes are manageable. It could certainly be used as a device for handicapping good players...</p>
<p>The Kensington software that comes bundled with the trackball does not support different profiles for different games (as far as I know), however there are four buttons on the mouse that you can map to one of many different input events. The scroll wheel is also a handy addition in games that require one.</p>
<h3>Conclusion ### {#concl}</h3>
<p>The only disadvantage to this trackball mouse is its price: currently selling for $80 on Amazon. This is pretty expensive for any pointing device, and it will be up to the user to determine whether this device is worth that amount of money. For me, it certainly was. Perhaps it's not entirely optimal for FPS gaming, but the Kensington Expert Mouse's superior tracking, excellent usability and the small touches such as the scroll ring make it in my opinion a must-buy for trackball users.</p>