<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
   <channel>
      <title>Vargoville</title>
      <link>https://bvargo.com/blog/</link>
      <description>Vargoville posts feed.</description>
      <atom:link href="http://bvargo.com/blog/rss.xml" rel="self"></atom:link>
      <language>en-us</language>
      <lastBuildDate>Sun, 19 Aug 2012 15:21:59 MDT</lastBuildDate>

      
      <item>
         <title>Fixing Old Themes for Enlightenment 17</title>
         <link>http://bvargo.com/2012/05/01/fixing-old-themes-for-enlightenment-17/</link>
         <pubDate>Tue, 01 May 2012 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2012/05/01/fixing-old-themes-for-enlightenment-17/</guid>
         <description>
            &lt;p&gt;My window manager of choice is &lt;a href=&quot;http://enlightenment.org/&quot;&gt;Enlightenment 17&lt;/a&gt;, which has been in development for at least the past seven years, when I started using it. While generally awesome, e17 has never had a stable release, which means that features sometimes break. Last November, my theme of choice, &lt;a href=&quot;http://exchange.enlightenment.org/theme/show/1594&quot;&gt;Milky&amp;#8217;s&lt;/a&gt;, stopped displaying the titlebar properly. Since the last release of the theme was from early 2010, I finally decided to learn about the e17 theming system and fix the problem.&lt;/p&gt;
&lt;p&gt;The only post I could find of someone with a similar issue was &lt;a href=&quot;http://forums.bodhilinux.com/index.php?/topic/2972-old-e17-themes-with-titlebar-problem/&quot;&gt;here&lt;/a&gt;. My problem can be summarized as follows: the title bar became &lt;strong&gt;extremely&lt;/strong&gt; short after the upgrade, as shown in the screenshot below. The titlebar text was unreadable. The close, minimize, and maximize buttons were unusable.&lt;/p&gt;
&lt;p&gt;Before fix:&lt;br /&gt;
&lt;img src=&quot;/blog/images/e17-titlebar-before.png&quot; title=&quot;Before fix&quot; alt=&quot;Before fix&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Without any good leads, I decompiled the &lt;a href=&quot;http://trac.enlightenment.org/e/wiki/Edje&quot;&gt;edje&lt;/a&gt; theme file with edje_decc and had a look around. The theme comprised of almost 44,000 lines of styling. Wow. Luckily, the border file, milky_border.edc, where I figured my problem was located, was only ~7500 lines long. Of that, only ~1000 lines, not including support macros, were for the default border group, which is where I was experiencing my error. If I could fix the default border type, then I could fix the other border types as well.&lt;/p&gt;
&lt;p&gt;Before starting this experiment, I knew nothing about edje files, so the following could be completely wrong. However, it appears that, at some point, the interpreted behavior for text switched from &amp;#8220;fit the text into the box&amp;#8221; to &amp;#8220;let the text overflow the box.&amp;#8221; (Alternatively, see the note at the end of this post, which notes how this might work.) The height of the text was the primary driver behind the height of the title bar, so after this change, only the border regions of the title bar were visible. Since these border regions were the same color, and the text overflowed, it looked like the border had shrunk.&lt;/p&gt;
&lt;p&gt;Solution: make the text area have a minimum size. The default theme file does not set the minimum height of the font size text area in pixels &amp;#8212; indeed, I have not taken the time to understand how the default theme is working without a height set &amp;#8212; but a kludge for Milky&amp;#8217;s theme is to set the minimum height of the text area to the font size of the text; this is 10 pixels for Milky at normal &lt;span class=&quot;caps&quot;&gt;DPI&lt;/span&gt; settings. Voilà, the theme looks proper once again. Ideally, the text area should resize itself to match the height of the text, but I have not yet figured out how to make this happen. (Again, see the note at the bottom.)&lt;/p&gt;
&lt;p&gt;After fix:&lt;br /&gt;
&lt;img src=&quot;/blog/images/e17-titlebar-after.png&quot; title=&quot;After fix&quot; alt=&quot;After fix&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Specific to Milky&amp;#8217;s theme, the following should be in the milk_border.edc file within each border group:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;part {
   name:           &amp;quot;title2&amp;quot;;
   type:           TEXT;
   mouse_events:   0;
   description {
      state: &amp;quot;default&amp;quot; 0.0;
      align: 1.0 0.0;
      visible: 0;
      min: 0 10;               // this is the new line
      rel1 {
         relative: 0.0  0.0;
         offset:   0    3;
      }
      rel2 {
         relative: 0.0  0.0;
         offset:   0    3;
      }
      text {
         text_source:   &amp;quot;e.text.title&amp;quot;;
         source:        &amp;quot;e.text.title&amp;quot;;
         min:           0 1;
         text_class:    &amp;quot;title_bar&amp;quot;;
      }
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The line marked above should be added to every title2 section in the file, so that each border type is corrected. To recompile the theme into a theme file, run the build.sh script, and import the resulting *.edj file.&lt;/p&gt;
&lt;p&gt;The &amp;#8220;correct&amp;#8221; fix: It seems that the &amp;#8220;min: 0 1;&amp;#8221; line in the text portion of the part should prevent the part from being resized to smaller than the text, depending on the values. However, no combination of values seemed to produce the desired effect, so I have left the line as-is, as there appears to be a further intricacy that I have not yet discovered.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Finding and Eliminating Duplicated Files</title>
         <link>http://bvargo.com/2012/04/25/finding-and-eliminating-duplicated-files/</link>
         <pubDate>Wed, 25 Apr 2012 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2012/04/25/finding-and-eliminating-duplicated-files/</guid>
         <description>
            &lt;p&gt;Fancy file systems are all the rage. &lt;a href=&quot;http://hub.opensolaris.org/bin/view/Community+Group+zfs/whatis&quot;&gt;&lt;span class=&quot;caps&quot;&gt;ZFS&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;https://btrfs.wiki.kernel.org&quot;&gt;btrfs&lt;/a&gt;, and even Microsoft&amp;#8217;s new &lt;a href=&quot;http://blogs.msdn.com/b/b8/archive/2012/01/16/building-the-next-generation-file-system-for-windows-refs.aspx&quot;&gt;ReFS&lt;/a&gt; include data deduplication features. However, these techniques can use a lot of memory, and new file systems are often not nearly as stable as tried and true file systems, such as &lt;a href=&quot;https://ext4.wiki.kernel.org/&quot;&gt;ext3/ext4&lt;/a&gt; or &lt;a href=&quot;http://oss.sgi.com/projects/xfs/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;XFS&lt;/span&gt;&lt;/a&gt;. Experimenting with file systems is fun; however, in this case, I am not about to trust all of my data to a new file system just to remove duplicate files. Instead, I decided to deduplicate my files using a few scripts. The end result: over 12GB of saved space after just a few minutes of scanning my hard drive. With hard drive prices sky high (but slowly coming down), this will help me last another 6 months before I have to upgrade my hard drives again.&lt;/p&gt;
&lt;p&gt;Out of approximately 1TB of data, I had 24G of total space occupied by duplicated files. This means that, at a minimum, I should be able to save 12G of space, assuming there are only two copies. However, for many of my photos, it turned out that I had three or four copies in different directories. &lt;span class=&quot;caps&quot;&gt;RAW&lt;/span&gt; photos are on the order of 15MB each for my camera, so this is quite a bit of wasted space. Now, I have largely eliminated duplicated files through removing excess files and hardlinking the remaining files. I use hardlinks for pictures, since I often to have a single picture in more than one directory, for easy browsing.&lt;/p&gt;
&lt;p&gt;Here is my quick script that will generate a SQLite database containing the md5 hash of every file in the current directory that is over 1MB in size:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# creates an index all files in the filesystem, path and md5&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# the database is named &amp;quot;index.db&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# bvargo&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;DBFILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;index.db&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# creates the databse&lt;/span&gt;
rm -f &lt;span class=&quot;nv&quot;&gt;$DBFILE&lt;/span&gt;
sqlite3 &lt;span class=&quot;nv&quot;&gt;$DBFILE&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;CREATE TABLE files (md5 text, path text)&amp;quot;&lt;/span&gt;;

&lt;span class=&quot;c&quot;&gt;# the magic that does everything&lt;/span&gt;
find . -type f -size +1M -print0 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   | xargs -0 md5sum &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   | sed &lt;span class=&quot;s1&quot;&gt;&amp;#39;s/^/INSERT INTO files (md5, path) VALUES (&amp;quot;/; s/  /&amp;quot;, &amp;quot;/; s/$/&amp;quot;);/&amp;#39;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   | sqlite3 &lt;span class=&quot;nv&quot;&gt;$DBFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Why the 1MB? I have a lot of code, and &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; and git tend to duplicate a number of files. For instance, many git scripts are duplicated between repositories. I do not wish to eliminate these duplicates, as I may change the files in the future. Since they do not contribute much to the total hard drive space used, I can skip them. Skipping small files also has the advantage of skipping a large number of files, reducing the number of hard disk seeks, and thus speeding the process of indexing the drive.&lt;/p&gt;
&lt;p&gt;If you wish to change this property, change the +1M in the find statement above. The rest of the find statement is just finding files under  the current directory and printing the filenames, delimited by null characters. xargs is then running md5sum on each file. The sed &lt;del&gt;statement&lt;/del&gt; hack converts the md5sum output to &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;. The &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; is passed to SQLite without any intermediate files.&lt;/p&gt;
&lt;p&gt;Once we have our index file, index.db, we can find duplicate files. The &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement will find all files that have an md5 hash that matches another file in the database. The name of all duplicated files is printed, along with the hash. From there, eliminate all except for one of the files to remove the duplicate entries. The utility is not smart enough to figure out which files you want removed and which files you want to keep!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# find duplicate files&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# replace $DBFILE with index.db if running from the command line&lt;/span&gt;
sqlite3 &lt;span class=&quot;nv&quot;&gt;$DBFILE&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;SELECT md5, path FROM files WHERE md5 IN&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;      (SELECT md5 FROM files GROUP BY md5 HAVING COUNT(md5) &amp;gt; 1)&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;      ORDER BY md5;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Before we delete anything, if you want to see how much space is taken up by files in the output set, run the following command. This is where I got the 24GB number from, as I noted above. Divide by two to get the minimum amount of space that you can save.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# to get the size saved:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# replace $DBFILE with index.db if running from the command line&lt;/span&gt;
sqlite3 &lt;span class=&quot;nv&quot;&gt;$DBFILE&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;SELECT path FROM files WHERE md5&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;      IN (SELECT md5 FROM files GROUP BY md5 HAVING COUNT(md5) &amp;gt; 1)&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;      ORDER BY md5;&amp;quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   | tr &lt;span class=&quot;s1&quot;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;\0&amp;#39;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   | du -shc --files0-from&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;-
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Happy deduplicating!&lt;/p&gt;
&lt;p&gt;Disclaimer: The &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; generation method is not completely robust, as it depends on the output format of md5sum. However, the null-delimited entries should mean that the script should work on all filenames, assuming the md5sum output remains constant. The last script snippet will break on file names that contain newlines, since I knew that none of my files contained newlines.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Hello World</title>
         <link>http://bvargo.com/2012/01/01/hello-world/</link>
         <pubDate>Sun, 01 Jan 2012 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2012/01/01/hello-world/</guid>
         <description>
            &lt;p&gt;Hello world! Again. Keeping with the tradition of writing more blog engines than blog posts, I now have &lt;em&gt;two&lt;/em&gt; new blog engines. I began writing a static blog site generated from source markup using shell scripts, but then I discovered &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;jekyl&lt;/a&gt; and &lt;a href=&quot;https://github.com/hyde/hyde&quot;&gt;hyde&lt;/a&gt;. I decided to go with jekyll. All of my old blog links should still work, but now it is easier for me to write new blog posts (go vim!).&lt;/p&gt;
&lt;p&gt;My New Year&amp;#8217;s resolution is to publish more of my projects (code or otherwise), so hopefully I will get around to posting about interesting things here. To start with, check out the two plugins I wrote for this blog &lt;a href=&quot;http://github.com/bvargo&quot;&gt;on github&lt;/a&gt;. The plugins create the tag pages and post summaries.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Lenovo T420 Internal Microphone and Linux</title>
         <link>http://bvargo.com/2011/09/24/lenovo-t420-microphone-and-linux/</link>
         <pubDate>Sat, 24 Sep 2011 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2011/09/24/lenovo-t420-microphone-and-linux/</guid>
         <description>
            &lt;p&gt;I recently &amp;#8212; by which I mean probably 6 months ago &amp;#8212; bought a Lenovo T420. The machine is amazing, except on one point: the microphone and headphone jacks are combined. For work, I need to be able to use Skype; it&amp;#8217;s not my favorite program in the world, but hey, it sort of works when the weather is right and the stars are aligned. However, with the integrated microphone/headphone port, I had a problem: I could not connect a microphone while still using my laptop&amp;#8217;s speakers. The T420 also includes a built-in stereo microphone, but this did not work correctly under Linux. I needed to make the internal microphone work.&lt;/p&gt;
&lt;p&gt;It turns out that I had too many audio drivers installed, since I had started with a liberal, non-tuned kernel configuration. Device Drivers &amp;#8594; Sound &amp;#8594; &lt;span class=&quot;caps&quot;&gt;ALSA&lt;/span&gt; &amp;#8594; &lt;span class=&quot;caps&quot;&gt;PCI&lt;/span&gt; sound devices &amp;#8594; Intel HD audio &amp;#8594; Conexand HD-audio codec support is the only required option. I also enabled reconfiguration support, jack plugging notification, and the &lt;span class=&quot;caps&quot;&gt;HDMI&lt;/span&gt; drivers, as well as power saving. Now the internal microphone shows up as Capture in alsamixer. To enable capture, press spacebar in alsamixer so that the L and R indicators come up along with &amp;#8220;&lt;span class=&quot;caps&quot;&gt;CAPTURE&lt;/span&gt;&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Now both the microphone and video camera work. (To get the video camera working, enable Device Drivers &amp;#8594; Multimedia support &amp;#8594; Video capture adapters &amp;#8594; V4L &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; devices &amp;#8594; &lt;span class=&quot;caps&quot;&gt;UVC&lt;/span&gt;.)&lt;/p&gt;
&lt;p&gt;Happy Skyping.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Copying Chromium/Google Chrome Search Engines</title>
         <link>http://bvargo.com/2011/05/29/copying-chromium-search-engines/</link>
         <pubDate>Sun, 29 May 2011 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2011/05/29/copying-chromium-search-engines/</guid>
         <description>
            &lt;p&gt;Chromium (the open source version of Google Chrome) has a great search engine feature that allows the user to search different websites directly from the omnibox (the address bar). I use this feature heavily; for example, &amp;#8220;wp Linux&amp;#8221; means search Wikipedia for the Linux article for my browser, &amp;#8220;bgo chromium&amp;#8221; means search bugs.gentoo.org for all bugs containing the term chromium, etc. All of these search engine features are configured from the &amp;#8220;Manage Search Engines&amp;#8221; screen under Preferences. Chromium will even add search engines as it finds them, through metadata embedded in some pages. For example, Amazon has this feature embedded in its page, so searching &amp;#8220;amazon.com Arduino&amp;#8221; will search for the Arduino on Amazon.&lt;/p&gt;
&lt;p&gt;But there&amp;#8217;s a problem, aside from some people not like search engines being added automatically. While Chromium seems to sync almost everything between multiple computers, search engines are not synced. Read on for how the search engines can be transferred from one machine to another without having to enter them all by hand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Chromium now support search engine synchronization. See &lt;a href=&quot;http://code.google.com/p/chromium/issues/detail?id=15548&quot;&gt;Issue 15548&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h1&gt;Backround&lt;/h1&gt;
&lt;p&gt;Chromium stores most settings in a set of SQLite databases. I will not detail SQLite, since the project has excellent documentation on the &lt;a href=&quot;http://sqlite.org/&quot;&gt;SQLite website&lt;/a&gt;, it will suffice to say that SQLite is an embedded, relational database. In particular, Chromium stores the search engines in a table called keywords in the &amp;#8220;Web Data&amp;#8221; database. These keywords can be exported and re-imported into another Chromium browser profile.&lt;/p&gt;
&lt;h1&gt;Getting Started&lt;/h1&gt;
&lt;p&gt;First, when doing any work with the SQLite database, ensure Chromium is not running. SQLite supports the locking of the database nicely, so you do not have to worry about corrupt data, but Chromium likes to keep the database locked more often than not.&lt;/p&gt;
&lt;p&gt;Second, find the profile directory in which Chromium keeps its data. On Linux, this is ~/.config/chromium/Default/, for the default profile. On Windows, if you are running Chrome, the profile should be somewhere such as C:\\Users\\username\\Application Data\\Google\\Chrome\\Default, for Windows Vista or Windows 7. Please substitute this path where I write ~/.config/chromium/Default/ later.&lt;/p&gt;
&lt;p&gt;Third, you will need the sqlite3 command-line interface for this tutorial, available from the &lt;a href=&quot;http://sqlite.org/&quot;&gt;SQLite website&lt;/a&gt;. This should already be present on most Linux machines and Macs. For Windows, choose the download page, and then look under &amp;#8220;Precompiled Binaries for Windows,&amp;#8221; particularly at the zip file with the shell.&lt;/p&gt;
&lt;p&gt;Finally, please note that this will &lt;span class=&quot;caps&quot;&gt;NOT&lt;/span&gt; synchronize the search engines. This is a one-way process, as written, though you could expand it to export from both computers, combine the results, and then use the new set of search engines on many computers.&lt;/p&gt;
&lt;h1&gt;Exporting the Data&lt;/h1&gt;
&lt;p&gt;Exporting the search engines is as easy as exporting the keywords table from SQLite. On the machine that you wish to export the search engines from:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sqlite3 ~/.config/chromium/Default/Web&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Data
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This will start the sqlite3 command-line interface. Then, to export the data from the keywords table:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;.output keywords_export.sql
.dump keywords
.quit
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now you have a file called keywords_export.sql in the directory from which you ran the sqlite3 command. Copy this to the machine on which you wish to import the search engines.&lt;/p&gt;
&lt;h1&gt;Importing the Data&lt;/h1&gt;
&lt;p&gt;Importing the data is even easier. Assuming that the export done in the previous step is called keywords_export.sql is in the working directory, the following will delete the old search engines and import the new search engines:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sqlite3 ~/.config/chromium/Default/Web&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Data &lt;span class=&quot;s2&quot;&gt;&amp;quot;DROP TABLE keywords&amp;quot;&lt;/span&gt;
sqlite3 ~/.config/chromium/Default/Web&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Data &amp;lt; keywords_export.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The last command will not work in a normal Windows shell, which does not support file redirection nicely. Instead, use the following in place of the last command, remembering to substitute for the location of the Web Data database:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;sqlite3 -init keywords_export.sql ~/.config/chromium/Default/Web&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Data .quit
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Start up Chromium and see your search engines restored.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;You should see your search engines copied from one machine to another. If you wish to see syncing of search engines in chromium or Google Chrome, please star &lt;a href=&quot;http://code.google.com/p/chromium/issues/detail?id=15548&quot;&gt;Issue 15548&lt;/a&gt; on the chromium project&amp;#8217;s issue tracker. Not only are you letting the developers know you wish to see this feature, but you are notified of all future updates regarding the feature request.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Arduino Installation Notes</title>
         <link>http://bvargo.com/2011/05/29/arduino-installation-notes/</link>
         <pubDate>Sun, 29 May 2011 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2011/05/29/arduino-installation-notes/</guid>
         <description>
            &lt;p&gt;I recently bought an Arduino Uno (thanks in part to SparkFun&amp;#8217;s free day, thanks SparkFun!), and I have finally gotten around to hooking it up to my main Linux box, which runs Gentoo. Some notes on problems I encountered getting everything working:&lt;/p&gt;
&lt;p&gt;1) The dev-embedded/arduino package in Porgage is extremely old. Use the overlay at git://gitorious.org/gentoo-arduino/arduino.git, or compile directly from the Arduino source.&lt;/p&gt;
&lt;p&gt;2) Despite what online documentation may say, the Uno does not use a &lt;span class=&quot;caps&quot;&gt;FTDI&lt;/span&gt; chip for serial communication, unlike the previous Arduinos. Instead, the ATmega328 firmware image takes care of the &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt;&amp;lt;&amp;#8212;&amp;gt;serial communication. As such, a different driver is required. When configuring a kernel, enable CONFIG_USB_ACM (Device Drivers &amp;#8594; &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; Support &amp;#8594; &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; Modem (&lt;span class=&quot;caps&quot;&gt;CDC&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;ACM&lt;/span&gt;) support) for support. The Arduino will most likely show up as /dev/ttyACM0, assuming no other &lt;span class=&quot;caps&quot;&gt;ACM&lt;/span&gt; devices are connected.&lt;/p&gt;
&lt;p&gt;3) The Uno firmware may have a bug in it that causes issues under Linux, depending on the version loaded. To update the firmware, follow the instructions &amp;#8220;here&amp;#8221;: http://arduino.cc/en/Hacking/DFUProgramming8U2.&lt;/p&gt;
&lt;p&gt;4) In Gentoo, there is a bug where the crossdev version of ld will not find the file avr5.&amp;#215;. For more information, see &lt;a href=&quot;http://bugs.gentoo.org/show_bug.cgi?id=147155&quot;&gt;Bug 147155&lt;/a&gt; in the Gentoo Bugzilla. For a quick fix, the following works, thanks to comment 61 on that bug, assuming an amd64 host:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usr/x86_64-pc-linux-gnu/avr/binutils-bin/2.20.1
ln -sf /usr/lib/binutils/avr/2.20.1/ldscripts ldscripts
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;5) The Arduino version of avrdude is different than the stock version. The modified version of avrdude can be found in the Arduino github repository (git://github.com/arduino/Arduino.git). If you try to use the stock version, you will probably get an error that looks something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;avrdude: Yikes!  Invalid device signature.
         Double check connections and try again, or use -F to override
         this check.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now everything works, and I&amp;#8217;ve finally started a few new projects that had gotten pushed to the side for the past two years.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Introduction to awk</title>
         <link>http://bvargo.com/2010/11/07/introduction-awk/</link>
         <pubDate>Sun, 07 Nov 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/11/07/introduction-awk/</guid>
         <description>
            &lt;p&gt;awk is a pattern scanning and processing language that is commonly used to process tabular data by either transforming the data in some way or producing a report about the data. The language is turing complete, and at least the &lt;span class=&quot;caps&quot;&gt;GNU&lt;/span&gt; version has file and network I/O capabilities. However, this introduction guide will not discuss the advanced features for the sake of brevity.&lt;/p&gt;
&lt;h1&gt;Common Usage&lt;/h1&gt;
&lt;p&gt;The most common, and probably the simplest, usage of awk is printing particular fields from a  tabular data source.&lt;/p&gt;
&lt;p&gt;Suppose that we have the following file, hp_dates:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Severus  Snape       January     9  1960
Arthur   Weasley     February    6
James    Potter      March       27 1960
Ron      Weasley     March       1  1980
Fred     Weasley     April       1  1978
George   Weasley     April       1  1978
Draco    Malfoy      June        5  1980
Harry    Potter      July        31 1980
Neville  Longbottom  July        30 1980
Ginny    Weasley     August      11 1981
Hermione Granger     September   19 1979
Bill     Weasley     November    29 1970
Lord     Voldemort   December    31 1926
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Further suppose that we want to print the years of birth, omitting all of the other data. Notice how the number of spaces between each field is variable. One might be tempted to use the cut command to do this. However, this will not work well with this input due to the column-aligned data instead of delimited data. However, we can easily print certain columns of data by using awk:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;{ print $5 }&amp;#39;&lt;/span&gt; hp_dates
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;What this does is reads the file hp_dates and runs the command for each line. In this case, the $5 indicates that the 5th field should be printed; $0 is a special case where the entire line (really the entire record &amp;#8212; see below) is printed. awk can also read from standard input, in which case the filename can be omitted. Also, notice how Arthur Weasley does not have a year associated with his birthday. awk will not throw an error in this case, but nothing will be printed for $5.&lt;/p&gt;
&lt;p&gt;Further suppose that we want to output both the first name and the year of birth, and this time our data is coming from standard input. Again, this is done fairly easily with awk:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;cat hp_dates | awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;{ print $1, $5 }&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;How This Works&lt;/h1&gt;
&lt;p&gt;awk consists of pattern/action pairs. When awk is run, the input is split into a number of records. By default, these records are separated by the newline character; see the RS variable below. For each record, if a pattern is matched, the associated action is performed. The general format is as follows:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;pattern { action1; action2 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Each action can be separated by semicolons, as shown, or the actions can be separated onto multiple lines without using semicolons.&lt;/p&gt;
&lt;p&gt;In the above examples, we omit the pattern, so the action will be performed for every line in the file. Also, we use a few default values above. The first default is the field separerator, by default whitespace. See the FS variable below. The second is the output field separator, which is inserted between the $1 and the $5 in the second example. This value is also a space by default. If we had omitted the comma, the two values would be printed together without any delimiter. See the &lt;span class=&quot;caps&quot;&gt;OFS&lt;/span&gt; variable below. Finally, we use the output record seperator, by default a newline, which separates records on output. See the &lt;span class=&quot;caps&quot;&gt;ORS&lt;/span&gt; variable below.&lt;/p&gt;
&lt;h1&gt;Special Variables&lt;/h1&gt;
&lt;p&gt;awk has a number of special variables, such as the &lt;span class=&quot;caps&quot;&gt;OFS&lt;/span&gt; (output field seperator) that was already mentioned above. As the dollar sign is used to retrieve fields from a record, the variables should be used without a dollar sign. For example, the variable NF would give the number of fields, while $NF would access the last field.&lt;/p&gt;
&lt;p&gt;Variables of particular interest:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;NR &amp;#8211; current count of the number of input records. The first record will be  1; the second will be 2, etc.&lt;/li&gt;
	&lt;li&gt;NF &amp;#8211; the number of fields in the current record.&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;FILENAME&lt;/span&gt; &amp;#8211; the current filename (- for standard input).&lt;/li&gt;
	&lt;li&gt;FS &amp;#8211; the field separator. The default is white space, meaning either tab characters, space characters, or a combination of the two.&lt;/li&gt;
	&lt;li&gt;RS &amp;#8211; the record separator. The default is a newline.&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;OFS&lt;/span&gt; &amp;#8211; the output field separator, the value inserted for a comma, as shown above. By default this is a space.&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;ORS&lt;/span&gt; &amp;#8211; the output record separator, the value that separates records for output. By default this is a newline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See more special variables in the &lt;a href=&quot;http://www.gnu.org/software/gawk/manual/gawk.html#Built_002din-Variables&quot;&gt;&lt;span class=&quot;caps&quot;&gt;GNU&lt;/span&gt; manual&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Another Example&lt;/h1&gt;
&lt;p&gt;Suppose that we want to emulate wc and print out the number of lines, words, and characters.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;BEGIN { print &amp;quot;File statistics (lines, words, characters):&amp;quot; }&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;{ w += NF; c += length + 1 }&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;END { print NR, w, c}&amp;#39;&lt;/span&gt; filename_here
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This file is devided into three parts:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;The first action is matched on &lt;span class=&quot;caps&quot;&gt;BEGIN&lt;/span&gt;, which is a pattern that matches only when awk is first executed, even if multiple files are specified. Note that the &lt;span class=&quot;caps&quot;&gt;FILENAME&lt;/span&gt; variable will be blank in the &lt;span class=&quot;caps&quot;&gt;BEGIN&lt;/span&gt; clause, because awk has not yet opened a file.&lt;/li&gt;
	&lt;li&gt;The second action does not have a pattern, so it will be run for each line. w is storing the number of fields, in this case the number of words because the default delimiter is spaces and/or tabs. c adds the number of characters in each record, plus one to include the newline characters that are not a part of each record. length is actually a function, and is shorthand for length($0) (where $0 is the entire record). length returns the number of characters in the provided argument.&lt;/li&gt;
	&lt;li&gt;The last action is matched by &lt;span class=&quot;caps&quot;&gt;END&lt;/span&gt;, which is similar to &lt;span class=&quot;caps&quot;&gt;BEGIN&lt;/span&gt; but matches when awk is about to exit. In this case, we use it to print out the statistics that we accumulated for each record. Remember that NR is the number of records (lines), which is why we did not increase a counter for each record.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Other Patterns&lt;/h1&gt;
&lt;p&gt;Suppose that we want to print the first name and year of birth for each of the Weasleys, excluding everyone else. We could use grep:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;grep Weasley hp_dates | awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;{ print $1, $5 }&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, we could use the pattern feature of awk:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;{if($0 ~ /Weasley/) { print $1, $5 }}&amp;#39;&lt;/span&gt; hp_dates
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The the if statement checks to see if the entire record contains the term Weasley. However, this is inside the action. Let&amp;#8217;s make it a pattern:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;$0 ~ /Weasley/ { print $1, $5 }&amp;#39;&lt;/span&gt; hp_dates
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Regular expressions are commonly used in this manner, so there is an even shorter expression:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;/Weasley/ { print $1, $5 }&amp;#39;&lt;/span&gt; hp_datesa
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note that there are no parenthesis around this shortcut. If parenthesis are added, the longer with the $0 should be used.&lt;/p&gt;
&lt;p&gt;In the above output, Arthur Weasley, who does not have a year, is still represented. Let&amp;#8217;s include only lines that have at least the number of records we want:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;/Weasley/ &amp;amp;&amp;amp; NF &amp;gt;= 5 { print $1, $5 }&amp;#39;&lt;/span&gt; hp_dates
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Try doing that with grep. The &amp;amp;&amp;amp; is a boolean operator, which will act as one would expect (&amp;#8220;and&amp;#8221;). || is also available (&amp;#8220;or&amp;#8221;).&lt;/p&gt;
&lt;p&gt;Finally, let&amp;#8217;s print the entire record instead of just the first name and the year of birth:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;/Weasley/ &amp;amp;&amp;amp; NF &amp;gt;= 5 { print }&amp;#39;&lt;/span&gt; hp_dates
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note that no argument is given to print. Like length, this will assume $0 as the argument, the equivalent of print($0), which prints the entire record. Note that when the record is printed in this way, the entire line, as it is originally represented in the file complete with spacing, is printed.&lt;/p&gt;
&lt;h1&gt;More on Patterns&lt;/h1&gt;
&lt;p&gt;Comma separated patterns can be used to turn an action on and off. Consider a file that has a &lt;span class=&quot;caps&quot;&gt;START&lt;/span&gt; marker and an &lt;span class=&quot;caps&quot;&gt;END&lt;/span&gt; marker around data that should be printed. We can print only the lines between these markers in addition to the markers themselves as follows:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;/START/,/END/ { print }&amp;#39;&lt;/span&gt; test_file
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In the previous example, /&lt;span class=&quot;caps&quot;&gt;START&lt;/span&gt;/,/&lt;span class=&quot;caps&quot;&gt;END&lt;/span&gt;/ could be replaced with any conditional, such as (NF0),(NF2). The first pattern will turn on the action, which will run for each record thereafter until the stop condition is met, which will execute the action for the last time and turn it off.&lt;/p&gt;
&lt;p&gt;One more final note on patterns and actions: each is executed independently of the others. This means that if two actions match a single record, and both print the record, then the record will be printed twice.&lt;/p&gt;
&lt;h1&gt;Further Information&lt;/h1&gt;
&lt;p&gt;This introduction has only briefely touched upon the basic features of awk. As I mentioned, the language is turing complete, and comes with much more functionality, including features found in most &amp;#8220;normal&amp;#8221; programming languages and libraries, such as for loops, complex if statements (with boolean operators), arrays (including multi-dimensional arrays and associative arrays), string functions, regular expressions, environment variables, number formatting (in addition to printf), random numbers, etc.&lt;/p&gt;
&lt;p&gt;For more information about awk, particularly gawk (the &lt;span class=&quot;caps&quot;&gt;GNU&lt;/span&gt; version), see the &lt;a href=&quot;http://www.gnu.org/manual/gawk/&quot;&gt;full manual&lt;/a&gt; or the man/info pages. &lt;a href=&quot;http://www.grymoire.com/Unix/Awk.html&quot;&gt;This page&lt;/a&gt; is also a nice guide.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>The Bluetooth Blues: Getting a Linux PC to use a GPS on an Android Device</title>
         <link>http://bvargo.com/2010/10/17/bluetooth-blues-getting-linux-pc-use-gps-android-d/</link>
         <pubDate>Sun, 17 Oct 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/10/17/bluetooth-blues-getting-linux-pc-use-gps-android-d/</guid>
         <description>
            &lt;p&gt;Bluetooth is one of the modern wonders of modern wireless technology. Whether you want to talk on the phone through your car or play a game on your Wii with a wiimote, you&amp;#8217;re using bluetooth. It is wonderful, when it works. When it doesn&amp;#8217;t, however, then it can be a royal pain.&lt;/p&gt;
&lt;p&gt;I set out with a simple goal: let me laptop use my phone&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt;. Easy, right? Well, not exactly.&lt;/p&gt;
&lt;p&gt;Bluetooth on Linux has never been easy to work with, or at least I have not found the right tools to make it easy. Verion 4 of BlueZ, the Linux bluetooth stack, did not help matters much either. With version 4, all of the configuration files changed. All of the command-line tools changed. BlueZ shifted to becoming a D-Bus-centric service. That may be great for people who run &lt;span class=&quot;caps&quot;&gt;KDE&lt;/span&gt; or Gnome and have a little panel applet to handle everything, but for me, the command-line user, all of my tools were taken away. For a long time, there simply were no command-line tools of the same quality as the old version 3 commands. You had to use D-Bus. I stayed at version 3 for a long time after it stagnated. It worked.&lt;/p&gt;
&lt;p&gt;Fast forward a year of so. Gentoo added two use-flags for version 4 of BlueZ: test-programs and old-daemons. All of my old &lt;span class=&quot;caps&quot;&gt;CLI&lt;/span&gt; tools are back in service. The new test programs also make several things much nicer.&lt;/p&gt;
&lt;p&gt;Enough introduction. How do I get my Android phone&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; available to my computer? To do this, there are a couple different pieces of software that I used. BlueZ, obviously, for the bluetooth stack on the computer. (BlueZ is also used in Android, but you do not really see it, since there is a nice UI.) &lt;a href=&quot;http://gpsd.berlios.de/&quot;&gt;GPSd&lt;/a&gt;, the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; service daemon, which is the de facto &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; on Linux. On the phone, I use a tool called &lt;a href=&quot;http://android.cajax.net/en/gps2bt&quot;&gt;&lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; 2 BT&lt;/a&gt;, which is available in the Market for free and outputs data in the &lt;span class=&quot;caps&quot;&gt;NMEA&lt;/span&gt; format over bluetooth.&lt;/p&gt;
&lt;p&gt;For the rest of this guide, I will assume that you have everything above installed. I will also assume that you are the root user when root permissions are needed. I will also assume that if you are not on Gentoo you can adapt the file paths / commands as needed.&lt;/p&gt;
&lt;h1&gt;Step 0: Figure out the &lt;span class=&quot;caps&quot;&gt;MAC&lt;/span&gt; address of the bluetooth interface on your computer and phone&lt;/h1&gt;
&lt;p&gt;On the computer:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;hcitool scan
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Which will output something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Devices:
   hci0     00:00:00:00:00:00
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;00:00:00:00:00:00 is the &lt;span class=&quot;caps&quot;&gt;MAC&lt;/span&gt; address of your computer. Now for the phone. Turn on bluetooth in the settings menu (settings &amp;#8594; wireless &amp;amp; networks &amp;#8594; check bluetooth) and then enter the bluetooth settings menu. In the bluetooth settings menu, note the name of the device and then check discoverable, which will make your phone visible to other devices for two minutes. Back on the computer:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;hcitool scan
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Which will output something similar to the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Scanning ...
   11:11:11:11:11:11    phone_name_here
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;Step 1: Pairing the devices&lt;/h1&gt;
&lt;p&gt;Do not leave the settings menu yet. It turns out that it is easier to pair the devices by initiating the connection from the phone, rather than the computer. Back on the computer, make the computer discoverable by using the bluez-test-adapter script. Second, start a pin program that will prompt for a pin when ready to pair:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;bluez-test-adapter discoverable on
simple-agent
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Back in the bluetooth menu on the phone, click scan for devices and look for your computer in the list of devices. Click on the device and enter a pin, such as a four digit number. Back on the computer you should see a prompt in the window running simple-agent asking for the pin. Enter the same number and press enter. The pairing should be successful; the phone should list the computer with &amp;#8220;paired but not connected&amp;#8221; listed below the name of the computer. If this is the case, hit ctrl-c on the computer to close simple-agent, as we don&amp;#8217;t need it anymore. Also, make the computer hidden again:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;bluez-test-adapter discoverable off
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;Step 2: Setting up the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;Back on the home screen of the phone, tap the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; 2 BT widget so that the slider on the right is up and the bar is green. This means that the phone is ready to accept &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; connections. Back on the computer, we are going to run a service discovery command to see that the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; is indeed visible.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;sdptool browse 11:11:11:11:11:11
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Remember, 11:11:11:11:11:11 is the &lt;span class=&quot;caps&quot;&gt;MAC&lt;/span&gt; address of the phone. Change accordingly for your phone. You should get back a bunch of different services, among which should be something similar to the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Service Name: Bluetooth GPS
Service RecHandle: 0x10003
Service Class ID List:
UUID 128: 00001101-0000-1000-8000-00805f9b34fb
Protocol Descriptor List:
&amp;quot;L2CAP&amp;quot; (0x0100)
&amp;quot;RFCOMM&amp;quot; (0x0003)
   Channel: 29
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;Step 3: Setting up &lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt;, which stands for radio frequency communication, is a protocol that emulates serial ports over Bluetooth. It can emulate multiple connections at once, so each connection is given a channel number. As an analogy, consider an IP and port in typical &lt;span class=&quot;caps&quot;&gt;TCP&lt;/span&gt;/IP. The IP is sort of like the &lt;span class=&quot;caps&quot;&gt;MAC&lt;/span&gt; in this case, and the channel is sort of like the port that the client connects to. This isn&amp;#8217;t actually how it works, but it may be helpful to think about it in this way.&lt;/p&gt;
&lt;p&gt;In the example above, the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; is on channel 29 (last line of the output). Configure the &lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt; connection, using that channel, by editing /etc/bluetooth/rfcomm.conf:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;rfcomm0 {
   # Automatically bind the device at startup
   bind yes;

   # Bluetooth address of the device
   device 11:11:11:11:11:11;

   # RFCOMM channel for the connection
   channel 29;

   # Description of the connection
   comment &amp;quot;Android GPS&amp;quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;Step 4: Configuring GPSd&lt;/h1&gt;
&lt;p&gt;Edit /etc/conf.d/gpsd, or the GPSd configuration file for other systems, to change the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; device. Above, we named the &lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt; connection rfcomm0. This will show up as /dev/rfcomm0. Use that device for GPSd.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;nv&quot;&gt;GPS_DEV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/dev/rfcomm0&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;Step 5: Test it out.&lt;/h1&gt;
&lt;p&gt;Make sure the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; icon on the phone is green, bluetooth is enabled on the phone and the computer, and the configured &lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt; channel matches the actual channel on the device. Start up gpsd (/etc/init.d/gpsd start). The daemon should be running now. Launch xgps, a test program included with GPSd, and see if it shows you your location. Try out other applications that use GPSd to get the location, such as kismet or gpsdrive. A list of many applications can be found at the GPSd &lt;a href=&quot;http://gpsd.berlios.de/&quot;&gt;homepage&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Troubleshooting&lt;br /&gt;
A few useful tools for debugging:&lt;/h1&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;rfcomm unbind rfcomm0
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;rfcomm bind rfcomm0
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This destroys and creates the /dev/rfcomm0 device. This is needed whenever you reconfigure the &lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt; settings. Restarting the bluetooth service should work too, but the commands above ensure the job gets done.&lt;/p&gt;
&lt;p&gt;You can manually connect with:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;rfcomm connect rfcomm0
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;However, the bluetooth connection should be started when GPSd is started, as GPSd tries to read from the file, so this should be unecessary.&lt;/p&gt;
&lt;p&gt;If you have the Android development tools installed, you can run the following to print the Android log:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;adb logcat
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Finally, if you keep getting errors, &lt;strong&gt;check your &lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt; channel&lt;/strong&gt;. For some reason, whenever I disconnect from the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; or restart the Android widget, the &lt;span class=&quot;caps&quot;&gt;RFCOMM&lt;/span&gt; channel changes. I have yet to find a better way to discover the correct channel each time.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Dynamic Ticks for Operating Systems</title>
         <link>http://bvargo.com/2010/09/13/dynamic-ticks-operating-systems/</link>
         <pubDate>Mon, 13 Sep 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/09/13/dynamic-ticks-operating-systems/</guid>
         <description>
            &lt;p&gt;Last week, I asked in my OS class how tickless operating systems use interrupts or other mechanisms to achieve lower power usage. I did not get my question answered, and have since read into the topic some more. Here is what I found.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning: I am not a kernel developer. I am a student. Some of this information may be outdated or outright wrong.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Background:&lt;/p&gt;
&lt;p&gt;&amp;#8220;Normal&amp;#8221; operating systems use system timer interrupt (a periodic timer &amp;#8220;tick&amp;#8221;) that fires on a periodic interval. This allows the kernel of the OS to update internal counters, perform any accounting, and switch processes (perform a context switch) if the current process&amp;#8217; time slice is done. This method has two primary downfalls: kernel timer resolution is limited to the tick rate, and an idle system uses unnecessary power by waking up from a sleeping state, checking to see if anything needs to be done, and then going back to sleep. These two functions are linked together. Suppose I am creating a real-time OS that has hard latency requirements, and I want to ensure the system is always responsive. Further suppose that I want this real-time OS to run on an embedded platform with low power requirements. To achieve more accurate timers, and then lower latencies, I can increase the rate of the timer interrupt. However, this also uses more power, as the system uses the &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt; and other hardware devices that may otherwise be idle to check if anything needs to be done.&lt;/p&gt;
&lt;p&gt;In Linux, the duration of a single tick of the system timer is called a jiffy. The actual duration of a jiffy in seconds is platform-dependent. On my box, by default, the timer frequency is set for 300Hz, so the timer fires every 1/300 of a second, which is just over 3ms.&lt;/p&gt;
&lt;p&gt;Now imagine that, even if your system is idle, it wakes up 300 times a second to see if it needs to do anything. However, at the same time, any system timers cannot be more accurate than 3ms, unless the rate is changed. This uses a lot of power if the system could otherwise be in a lower power state. As an analogy, consider setting your alarm clock so that you stop whatever you are doing every 4.8 minutes, even in the middle of the night, to see if it is time to go to class. You wouldn&amp;#8217;t be able to get any sleep, and you would not be able to focus on what you are doing for more than 4.8 minutes. Furthermore, if you check if it is time to go to class 5.3 minutes before class, you would have to wait another 4.8 minutes before you check again and realize that you have to go to class. This could leave you running for class if it turns out you only have 30 seconds left before class starts. Wouldn&amp;#8217;t it be nice if you could set the alarm clock so that it left you just enough time to get to class, and you wouldn&amp;#8217;t have to check every 4.8 minutes to see if it was time to go? In other words, wouldn&amp;#8217;t it be nice if we could set an accurate timer so that it would go off exactly when we needed it to?&lt;/p&gt;
&lt;p&gt;In this analogy, the course of the day is a second for your computer, and checking if it is time to go to class is equivalent to updating the computer&amp;#8217;s internal counters and checking for timer events. Hardware devices generate interrupts when they have something to say; wouldn&amp;#8217;t it be nice if we could do the same for internal software events too? Clearly the case of checking the clock every 4.8 minutes to see if it is time to go to class is not optimal. If you really want to extend the analogy, consider the context switch to be the 30 seconds it takes you to roll out of bed and wake up. Having an alarm clock go off exactly when it needs to is the equivalent of a controllable timer interrupt; the timing is far more precise compared to checking the clock every so often, and you get some sleep at night.&lt;/p&gt;
&lt;p&gt;Enter tickless operating systems.&lt;/p&gt;
&lt;p&gt;Tickless operating systems abolish the periodic tick, either when idle or completely, and use specific hardware to only wake up when necessary. This saves power when idle, and gives more processing time to the user when not idle. It also allows the accuracy of internal timers to be as accurate as the hardware allows, as there is no power/accuracy tradeoff. For example, if the OS knows that it does not need to wake for another 1.5 seconds, for example when the system is idle, then it can put the processor in a low power state for the entire 1.5 seconds. Hardware interrupts can still wake the system, so this is transparent to the user if implemented correctly. These little power savings add up.&lt;/p&gt;
&lt;p&gt;There is still a timer interrupt that is fired when requested, but the difference is that the OS is specifically requesting the timer to fire at a certain time and only when needed.&lt;/p&gt;
&lt;p&gt;More information:&lt;/p&gt;
&lt;p&gt;I mainly referenced Linux while looking for the answer to my question, as that is what I use, and the sources and developer messages are available for browsing. Of course some of this is probably oversimplified. For more information for Linux, which will also turn up general information, look for NO_HZ, dyntick, clockevents, or high resolution timers. NO_HZ is the kernel option that makes the OS tickless. dyntick and clockevents are part of the kernel. High resolution timers are more general. Linux has had a number of architecture-specific implementations of dynamic ticks since it was implemented for the s390 architecture in 2.6.6 in 2004. clockevents and dyntick, which provide a general &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for timing events, were merged into the mainline kernel for 2.6.19 in early 2007.&lt;/p&gt;
&lt;p&gt;Interesting links:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://lwn.net/Articles/223185/&quot;&gt;Clickevents and dyntick&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://kerneltrap.org/node/6750&quot;&gt;High-Res Timers and Tickless Kernel&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Lots of messages on the &lt;span class=&quot;caps&quot;&gt;LKML&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
         </description>
      </item>
      
      <item>
         <title>Backgrounds</title>
         <link>http://bvargo.com/2010/09/13/backgrounds/</link>
         <pubDate>Mon, 13 Sep 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/09/13/backgrounds/</guid>
         <description>
            &lt;p&gt;If you hadn&amp;#8217;t noticed, the background on this site changes every time you load the page. While I&amp;#8217;ve had the background collection for some time &amp;#8212; since high school actually &amp;#8212; I had forgotten that some of the backgrounds actually came from one of my friends, and I did not attribute this fact. I would like to fix this, especially since he made the cool images himself in gimp and has graciously let me continue using them. Take a look at his &lt;a href=&quot;http://www.tjhsst.edu/~jboning/&quot;&gt;high school site&lt;/a&gt;, where he has some more cool artwork in a changing background. You&amp;#8217;ll also notice that his loading mechanism is more efficient than mine.&lt;/p&gt;
&lt;p&gt;Some of the other backgrounds come from another project I used to work on during high school, &lt;a href=&quot;http://iodine.tjhsst.edu/&quot;&gt;iodine&lt;/a&gt;, our school&amp;#8217;s intranet.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>New Blog Engine</title>
         <link>http://bvargo.com/2010/08/19/new-blog-engine/</link>
         <pubDate>Thu, 19 Aug 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/08/19/new-blog-engine/</guid>
         <description>
            &lt;p&gt;I haven&amp;#8217;t updated this blog in awhile, and this is partly due to the fact that I disliked the blog engine I was using, Serendipity. It&amp;#8217;s not that Serendipity is bad, but rather that it simply tries to do too much. It is too flexible, at least for what I needed it for, but yet some things that I consider core features did not work properly. The biggest issue I had was combining markup and code syntax highlighting (geshi). In addition, once I had written a post and it looked good in the preview interface, the published version always differed in some way.&lt;/p&gt;
&lt;p&gt;I have developed my own blog engine now. It has three simple features: posts (with code syntax highlighting and markdown), comments (also with code syntax highlighting and markdown), and &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt;/Atom feeds. Will this make me update this blog more often? I do not know. At least the blog engine will not be in my way anymore.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Functional Programming with PHP</title>
         <link>http://bvargo.com/2010/06/12/functional-programming-php/</link>
         <pubDate>Sat, 12 Jun 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/06/12/functional-programming-php/</guid>
         <description>
            &lt;p&gt;Wait, what? You can do functional programming in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;? Doesn&amp;#8217;t that make &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; even more messy? Why would you do such a thing? In this case, no, it makes my code cleaner.&lt;/p&gt;
&lt;p&gt;Background: I am developing an application (in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; &amp;#8211; no comments on that please) that uses a &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; architecture (Model View Controller). I designed the framework myself, with some helper functions pulled from an older project that I used to work on. There is no cruft; there is little messiness associated with &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; projects; it does only what I need in a logical manner. More importantly, the framework lets me focus on my application without having to worry about backend stuff. For database access, I use ADOdb with an &lt;span class=&quot;caps&quot;&gt;OOM&lt;/span&gt; similar to ActiveRecord. For templates, I use Smarty.&lt;/p&gt;
&lt;p&gt;Across many pages in my application, I need to sort tabular data that is displayed to the user. Seems simple enough, right? Django handles this by having an inner class, Meta, that can define the ordering of objects returned from QuerySets. That, in my opinion, is the wrong way to go about sorting data in a template. Why should my model be defining the order in which data is displayed to the user? django-sorting has some automagic sorting functions, but there is no way to specify the default sorting order. Back in my &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; application, I did not want to specify the sorting order in my &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; code. The sort ordering belongs in the template, from which the data is displayed. Since I use Smarty, I had to find a way to make this happen. My solution is a Smarty attribute, sortby, which will magically take a string of fields to sort by and somehow sort the data.&lt;/p&gt;
&lt;p&gt;First, let us attack the problem of sorting itself. &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; has an array of sorting functions: sort, uksort, usort, and uasort. All, except for sort, take a callback comparison function that is responsible for comparing two elements. Even C has something similar; qsort takes a base pointer, the number of elements, the size of each element, and a function pointer to a comparison pointer. Back to &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;, this means we would do something like this for something simple:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// the comparison function&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// some initial data&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// actually do the sort&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;usort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;compare&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// do stuff with sorted data here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;However, those comparison functions get redundant and messy. &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; allows anonymous (lambda) functions, so we could do something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// some initial data&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// sort, defining the comparison function as an anonymous function&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;usort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// do stuff with sorted data here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Maybe that is a little better; I personally think it is still messy. What if I want to sort multiple items though? I have to define that comparison function twice now, if I still want it to be an anonymous function. More importantly though, this does not work in Smarty. I do not want to be writing sorting &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; code in my template. What I need is a function that will write a sorting function for me. I want to be able to do something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// some initial data - instances of the Person class&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//$people - assume it&amp;#39;s already assigned&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// actually do the sort&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;uasort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;first_name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;last_name&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;-#age&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That would be awesome. I do not have to worry about defining my own comparison function. sortby somehow knows how to access the correct fields of my People class and produces a comparison function that will first try sorting by the person&amp;#8217;s first name, then the last name, and then the age, in reverse. The &amp;#8220;-#&amp;#8221; means that I want age to be sorted in a numeric manner and in reverse. Let&amp;#8217;s see how we can make this happen. My solution:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;  1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// generates a function that can be used for comparisions while sorting&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  2&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// in order, compares by:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  3&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    object-&amp;gt;field()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  4&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    object-&amp;gt;field&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  5&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    object[&amp;#39;field&amp;#39;]&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  6&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// if a field is not given, then the data is compared directly&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  7&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// modifiers:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  8&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    prefix &amp;#39;-&amp;#39; to do a reverse sort&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  9&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    prefix &amp;#39;#&amp;#39; to sort numerically / direct comparison&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 10&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    prefix &amp;#39;-#&amp;#39; to sort numerically / direct comparison in reverse&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 11&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// example:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 12&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    sortby(&amp;quot;-name, #age&amp;quot;) returns a function that first compares name in&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 13&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//    reverse and, if those are equal, then compares by age numerically&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 14&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 15&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 16&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// caches generated functions&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 17&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$sort_funcs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 18&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt; 19&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$sort_funcs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 20&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 21&lt;/span&gt;       &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;compare = 0;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 22&lt;/span&gt;       &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 23&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 24&lt;/span&gt;          &lt;span class=&quot;nv&quot;&gt;$direction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 25&lt;/span&gt;          &lt;span class=&quot;nv&quot;&gt;$number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 26&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 27&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 28&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$direction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;-1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 29&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 30&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 31&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;#&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 32&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 33&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 34&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 35&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 36&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 37&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 38&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// assume a direct sort of data, since no fields were given&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 39&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 40&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 41&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 42&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 43&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 44&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;is_numeric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 45&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 46&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// must be the index of an array - variables/functions start with&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 47&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// letters&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 48&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 49&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            if(is_array(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a) &amp;amp;&amp;amp; is_array(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b) &amp;amp;&amp;amp; isset(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;]) &amp;amp;&amp;amp; isset(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;]))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 50&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            {&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 51&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 52&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 53&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            }&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 54&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            else&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 55&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            {&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 56&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               // bad key given&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 57&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = 0;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 58&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = 0;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 59&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            }&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 60&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 61&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 62&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 63&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 64&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 65&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            if(is_numeric(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a) &amp;amp;&amp;amp; is_numeric(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 66&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            {&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 67&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 68&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 69&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            }&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 70&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            else if(method_exists(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a, &amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;) &amp;amp;&amp;amp; method_exists(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b, &amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 71&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            {&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 72&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a-&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 73&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b-&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 74&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            }&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 75&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            else if(isset(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a-&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;) &amp;amp;&amp;amp; isset(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b-&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 76&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            {&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 77&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a-&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 78&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b-&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 79&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            }&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 80&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            else if(is_array(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a) &amp;amp;&amp;amp; is_array(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b) &amp;amp;&amp;amp; isset(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;]) &amp;amp;&amp;amp; isset(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;]))&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 81&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            {&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 82&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 83&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;b[&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;#39;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 84&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            }&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 85&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            else&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 86&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            {&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 87&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya = 0;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 88&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb = 0;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 89&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            }&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 90&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 91&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 92&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 93&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 94&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;if(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya &amp;gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb) return &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$direction&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; * 1;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 95&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;if(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya &amp;lt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb) return &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$direction&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; * -1;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 96&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 97&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 98&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 99&lt;/span&gt;             &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;if ( (&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;compare = strcasecmp(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keya, &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keyb)) != 0 ) return &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$direction&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;compare;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;100&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;101&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;102&lt;/span&gt;       &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;return $compare;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;103&lt;/span&gt;       &lt;span class=&quot;nv&quot;&gt;$sort_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$sort_funcs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;create_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;$a, $b&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;104&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;105&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;106&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;107&lt;/span&gt;       &lt;span class=&quot;nv&quot;&gt;$sort_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$sort_funcs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;108&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;109&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$sort_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;110&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Whoo. Get all that? Let&amp;#8217;s go through some it.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Lines 17-19: $sort_funcs is an associative array. After the sortby function produces a comparison function and &amp;#8220;compiles&amp;#8221; it into an actual function, it caches it so that further sorts will use use the already-created function. Why generate the same function twice?&lt;/li&gt;
	&lt;li&gt;Line 21: $code is going to be a string that makes up the function we are building. We will turn it into an actual, callable function later.&lt;/li&gt;
	&lt;li&gt;Line 24: $direction and $number control which direction we will sort in for a particular key and whether the sort is numeric (&amp;#8220;100&amp;#8221; &amp;lt; &amp;#8220;90&amp;#8221; but 90 &amp;lt; 100)&lt;/li&gt;
	&lt;li&gt;Lines 26-35: Set $direction and $number appropriately for the current key.&lt;/li&gt;
	&lt;li&gt;Line 36: If someone calls the function with sortby(&amp;#8217;&amp;#8217;), assume that we want the elements of the array to be directly compared.&lt;/li&gt;
	&lt;li&gt;Line 44: If someone calls the function with sortby(&amp;#8220;5&amp;#8221;), assume that the elements being sorted are themselves arrays, and we want to sort by a particular element of the array. Functions and variables cannot start with numbers.&lt;/li&gt;
	&lt;li&gt;Line 62: With the other checks out of the way, try to figure out what the passed arguments actually are. Are they numeric (line 65)? Are they methods that we should call (line 70)? Are they attributes in the object (line 75)? Are they keys in an associative array (line 80)? If none of these are valid, set $keya and $keyb to 0, and sortby just won&amp;#8217;t sort the function.&lt;/li&gt;
	&lt;li&gt;Lines 92-100: Add code that returns the proper response for the field.&lt;/li&gt;
	&lt;li&gt;Line 22 &amp;#8211; 101: All of this is in a loop for each field that is to be sorted. Additional code is added to the $code string to support supporting successive fields. The proper response is returned by lines 92-100 as soon as the two elements being compared are different, and the later code will not be run in this case.&lt;/li&gt;
	&lt;li&gt;Line 102: If we get all the way to this point, $compare will still be 0 because the two objects being compared appear to be equal, or none of the comparison methods work. Return.&lt;/li&gt;
	&lt;li&gt;Line 103: This is where the magic happens. This takes $code, which is still a string, and turns it into a proper callable function. It puts the function into the cache.&lt;/li&gt;
	&lt;li&gt;Line 109: This returns the sorting function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So this function makes the magic &amp;#8220;uasort($people, sortby(&amp;#8221;first_name&amp;quot;, &amp;#8220;last_name&amp;#8221;, &amp;#8220;-#age&amp;#8221;));&amp;quot; work pretty nicely. But how does this work in Smarty? It&amp;#8217;s still a &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; function. One last little piece is required, a Smarty plugin:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// smarty modifier: sortby&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// allows arrays of named arrays, objects with functions, or objects with&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// fields to be sorted by a given field or fields&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;smarty_modifier_sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$arr_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$sortfields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;uasort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$arr_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sortby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$sortfields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$arr_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Call it modifier.sortby.php, to tell Smarty that this is a modifier, if you put it in a directory Smarty is already searching for functions. If you do not have such a directory, make sure the following line is run, which will add the modifier to a Smarty instance, in this case called $smarty.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;php&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$smarty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register_modifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;sortby&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;smarty_modifier_sortby&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now I can use the sortby modifier in Smarty. Going back to my example of a Person, assume that a Person has a public variable $best_friend, which is another Person object. Now, using this Smarty attribute, I can do something like this in my template:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;smarty&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$people&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|@&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sortby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;best_friend-&amp;gt;first_name,best_friend-&amp;gt;last_name,#best_friend-&amp;gt;age,-#age&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;What will this do? It will loop over all of the objects in $people, sorted by the person&amp;#8217;s best friend&amp;#8217;s first name, the person&amp;#8217;s best friend&amp;#8217;s last name, the person&amp;#8217;s best friend&amp;#8217;s age, and finally by the person&amp;#8217;s age (numerically, in reverse). Within the loop, the variable $person is available, so I can display the details of each person. How does the &amp;#8220;best_friend&amp;#8594;first_name&amp;#8221; work? best_friend is a public variable in the Person instance stored in $people. In the sortby function, this expands to &amp;#8220;$a&amp;#8594;best_friend&amp;#8594;first_name&amp;#8221;, which is valid, so it works.&lt;/p&gt;
&lt;p&gt;This sure beats writing a bunch of comparison code somewhere else in my application every time I want to sort something. Of course it may not work for everything; I have not thoroughly tested it. Released under the &lt;span class=&quot;caps&quot;&gt;MIT&lt;/span&gt; license.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>BitlBee - Changing the Way I IM</title>
         <link>http://bvargo.com/2010/05/22/bitlbee-changing-way-i-im/</link>
         <pubDate>Sat, 22 May 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/05/22/bitlbee-changing-way-i-im/</guid>
         <description>
            &lt;p&gt;It is not very often that a piece of software dramatically changes my workflow. A few years ago, I largely stopped switching OSes, browsers, email clients, window managers, IM clients, etc. I settled with what I had, as it was largely good enough. While I have switched browsers since then (Firefox &amp;#8594; Chromium; more in another post), the workflow isn&amp;#8217;t dramatically different. Most of the keyboard shortcuts are even the same. So after a friend pointed me to &lt;a href=&quot;http://www.bitlbee.org&quot;&gt;Bitlbee&lt;/a&gt;, an IM client, and I started to use it, I was hooked. BitlBee is an IM client, but it is unlike any other IM client that I have seen. I did not only change applications, but I fundamentally changed how I access IM services.&lt;/p&gt;
&lt;p&gt;Traditionally, I have used Gaim for IM, even on Windows. Since I was running Linux, the standard &lt;span class=&quot;caps&quot;&gt;AIM&lt;/span&gt; client (yes, they did have one!) was awful. I have no idea if it has improved since then; I have not looked. Eventually Gmail and Google Talk came around, so I added a Jabber/&lt;span class=&quot;caps&quot;&gt;XMPP&lt;/span&gt; account to my arsenal. Then I was dragged into getting a Facebook account, and Facebook now supports Jabber/&lt;span class=&quot;caps&quot;&gt;XMPP&lt;/span&gt; for chat as well. Gaim (now called &lt;a href=&quot;http://pidgin.im/&quot;&gt;Pidgin&lt;/a&gt;) let me keep up, and so I never switched to anything new. Somewhere in there I started using &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt;, primarily for connecting to &lt;a href=&quot;http://freenode.net/&quot;&gt;freenode&lt;/a&gt;. Pidgin is pretty awful when it comes to &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt;; it simply is not built for it. Instead, I use &lt;a href=&quot;http://irssi.org/&quot;&gt;irssi&lt;/a&gt; inside a &lt;a href=&quot;http://www.gnu.org/software/screen/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;GNU&lt;/span&gt; Screen&lt;/a&gt; session. I liked the always-on nature of irssi, as it runs on my server, and looked for a way to do the same with IM. I could use a text client, such as pork or mcabber, but then I would have one program for each protocol, which I certainly did not want. I could also switch everything to Jabber/&lt;span class=&quot;caps&quot;&gt;XMPP&lt;/span&gt;, using transports for other protocols, but then I would still have irssi and some other piece of software for chatting. Enter BitlBee.&lt;/p&gt;
&lt;p&gt;As I mentioned, BitlBee is a fundamentally different IM client. Not only is it a client, but it is also a server, an &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; server. It is not an &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; server in the traditional sense; instead, it presents all of your IM buddies as other &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; users inside a control channel (&amp;amp;bitlbee). Active users (not away or idle) are marked as having voice in the channel, while those that are away or idle do not have voice. To talk to a buddy, you can address chats to that user in the control channel, or you can query them. Unlike a normal &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; channel, only that buddy will see the text you address to them in the control channel. When a buddy logs off, the user leaves the control channel. Special commands in the control channel allow you to access more detailed information about the buddy, or you can use a standard /whois &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; command. More special commands allow for setting up IM accounts, accessing a full buddy list, etc. Let&amp;#8217;s take a look at how to get started quickly with BitlBee. I&amp;#8217;m only going to cover &lt;span class=&quot;caps&quot;&gt;AIM&lt;/span&gt; and Jabber, as that&amp;#8217;s all I use, but BitlBee supports other IM protocols as well, and it even supports Twitter.&lt;/p&gt;
&lt;p&gt;Why is this important to me? It means I can access all of my chatting services, from Facebook to &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt;, from a single client: irssi (or any other &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; client, should I decide to switch).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First step:&lt;/strong&gt; Install and start the server.&lt;/p&gt;
&lt;p&gt;As this is OS/distro-dependent, I&amp;#8217;m going to skip this. I will assume you can figure it out. If you would rather use a public server, there are a number available, which are listed on the BitlBee website. However, I would recommend using your own, unless you want to give your IM passwords out to third parties.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second step:&lt;/strong&gt; Connect to the server from the &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; client.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;/connect localhost
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Substitute localhost with your server name, if applicable. Notice I used /connect, not /server. The latter will close any other &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; connections, while the former will not. This means I can be connected to freenode and my BitlBee server at the same time. To send commands to a specific server, execute the following in the status window:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;/window server &amp;lt;connection_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Read the quickstart guide if you wish; it&amp;#8217;s fairly comprehensive, and will guide you through the rest of the setup process. If you are impatient, keep following along here to get started quickly, then you can head back to the quickstart guide to read the rest, as I&amp;#8217;m not going to cover every feature (groupchats, etc).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Third step:&lt;/strong&gt; Setup your account with the BitlBee server.&lt;/p&gt;
&lt;p&gt;In the control channel (&amp;amp;bitlbee), execute the following (do the same for all following commands):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;register &amp;lt;password_here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;BitlBee will associate this password with your current nick. Then, when you connect in the future, you just have to identify, either using the identify command or standard identification methods for &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt;, and you will have access to your accounts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fourth step:&lt;/strong&gt; Setup your IM accounts.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account add &amp;lt;protocol&amp;gt; &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To set &lt;span class=&quot;caps&quot;&gt;SSL&lt;/span&gt; (find the account number with &amp;#8220;account list&amp;#8221;):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account set &amp;lt;account_num&amp;gt;/ssl true
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To force &lt;span class=&quot;caps&quot;&gt;TLS&lt;/span&gt; (the default is try, which falls back to plaintext if not available):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account set &amp;lt;account_num&amp;gt;/tls true
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;AIM&lt;/span&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account add oscar my_screenname my_password
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Google Talk:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account add jabber my_username@gmail.com my_password
account set &amp;lt;account_num&amp;gt;/tls true
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Google Talk (for Google Apps, e.g. most college campuses):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account add jabber my_username@some_domain.example.com my_password
account set &amp;lt;account_num&amp;gt;/tls true
account set &amp;lt;account_num/server talk.google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Facebook:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account add jabber my_facebook_username@chat.facebook.com
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note that Facebook does &lt;span class=&quot;caps&quot;&gt;NOT&lt;/span&gt; support encryption, while Google Talk requires it. This means all of your chats to Facebook will be sent in plaintext, which allows snoopers to listen in on your conversation, especially if you use an unencrypted wireless access point. (Note that the in-browser chat client also runs over &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;, so the same is true.) However, your password is encrypted using a &lt;span class=&quot;caps&quot;&gt;DIGEST&lt;/span&gt;-MD5 method prior to being sent over the connection to Facebook, so your password is fairly secure.&lt;/p&gt;
&lt;p&gt;After you have setup your accounts and account settings, save:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;save
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Fifth step:&lt;/strong&gt; Logging in to your accounts.&lt;/p&gt;
&lt;p&gt;By default, BitlBee will connect to all accounts that have the auto_connect account property set to 1. However, to get started now, do the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account on
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Sixth step:&lt;/strong&gt; Making the channel nicks better.&lt;/p&gt;
&lt;p&gt;Notice that, by default, BitlBee will use a buddy&amp;#8217;s username or handle as their nick in the channel. If, like me, you have aliases set up on the server, this is rather annoying. In the case of Facebook, this is especially annoying as Facebook Chat does not actually use the usernames of your friends. Instead, it uses negative numbers. Well isn&amp;#8217;t that helpful. Thankfully, BitlBee will let us change this behavior (added in version 1.2.5):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;account set &amp;lt;account_num&amp;gt;/nick_source full_name
save
account off &amp;lt;account_num&amp;gt;
account on &amp;lt;account_num&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Instead of using full_name, you can also use first_name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Seventh step:&lt;/strong&gt; Chatting.&lt;/p&gt;
&lt;p&gt;To chat with a user, simply address them in the control channel &amp;#8220;username: Hey, I&amp;#8217;m using BitlBee&amp;#8221; or query them &amp;#8220;/q username&amp;#8221;. BitlBee will remember which method you use to talk to the user, so the response will come back to the same window. The default for incoming messages starting a conversation can also be set (&amp;#8220;set private true/false&amp;#8221;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Final step:&lt;/strong&gt; Go read the documentation.&lt;/p&gt;
&lt;p&gt;As I said, BitlBee can do much more than this quick guide shows. Away and status messages, adding or removing users, blocking users, renaming users, group chats, buddy list interaction, typing notices, and simulating a netsplit are just some of the features I did not cover. BitlBee is a pretty powerful piece of software, and I&amp;#8217;m glad that someone pointed it out to me.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Motorola Droid</title>
         <link>http://bvargo.com/2010/05/17/motorola-droid/</link>
         <pubDate>Mon, 17 May 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/05/17/motorola-droid/</guid>
         <description>
            &lt;p&gt;My first cell phone was the &lt;a href=&quot;http://www.motorola.com/motoinfo/product/details.jsp?globalObjectId=82&quot;&gt;Motorola e815&lt;/a&gt;, one of the first 3G-enabled phones on the market. It was a great little phone that could get a signal in a canyon in the middle of nowhere, far from where Verizon said it should. Before Verizon killed the program, it also gave me 3G Internet access at the expense of my minutes via a bluetooth connection to my laptop.&lt;/p&gt;
&lt;p&gt;For Christmas and my birthday this past year, I got a new phone: a Motorola Droid, which runs Android. In some ways it is a step back, but in even more ways it is a huge leap forward. The step back is of course battery life; it seems I am charging it every 20 seconds. The huge leap forward is the number of features it offers, of course. Web browsing, Google Voice integration (one of my favorite features), email at your fingertips, and full-featured navigation complete with street view and live traffic are just some of the main features. Those are the features covered in numerous reviews, so I&amp;#8217;m going to sail right over them and skip to what makes this phone special.&lt;/p&gt;
&lt;p&gt;First though, I want to differentiate this phone from that &amp;#8220;other&amp;#8221; popular phone, the iPhone. I wanted the original iPhone when it came out. There, I admitted it: I used to like the iPhone. However, Android is much much better for someone like me, a developer. Android is open. The iPhone is a classic case of Apple control, a walled garden. Apple has rejected applications because they might possibly &amp;#8220;confuse the user.&amp;#8221; On Android, there are so many applications that may not be the most intuitive, but are awesome to the point you wondered how you lived without them. Can my phone be a &lt;span class=&quot;caps&quot;&gt;FTP&lt;/span&gt; server? Check. &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; server? Check. &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; client? Check. &lt;span class=&quot;caps&quot;&gt;VNC&lt;/span&gt; client? Check. &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; device with &lt;span class=&quot;caps&quot;&gt;GPX&lt;/span&gt; export? Check (it also syncs with Google Maps). A barcode scanner? Check, complete with barcode generation for sharing with other phones. Translation tool? Check. Gaming platform? Check, and I can even use a wiimote to control the games. The phone even comes from Verizon loaded with a proxy that you can use via &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt;, and with some playing around you can even make it a wireless access point via Wifi or Bluetooth. The iPhone can of course do many of these things too, but for every story where I hear of Apple blocking some innovative application for some obscure reason, I find that my Droid lets me do whatever Apple will not. Oh yeah, and the Droid has a keyboard. After experiencing the disaster in &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt; design that is the N800, I decided that a physical keyboard is a prerequisite for almost any mobile computing device I purchase. Indeed, after using the iPhone for the first time, I am extremely happy the Droid has a keyboard.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s take a look at some of these features in more detail. Note, many of these features require installation of applications from the Android Market.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; Proxy&lt;/strong&gt; &amp;#8211; The phone comes loaded with a proxy all ready to go. Just install the Android developer tools on your desktop or laptop, and you have port forwarding between your computer and your phone. The same developer tools also give you shell access to your phone, no additional software installation on the phone required. Install Privoxy on your phone, and your phone is now an &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; proxy accessible from your computer.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Google Goggles&lt;/strong&gt; &amp;#8211; Google Goggles is one of those magical Google labs products. Take a picture of text, and it scans it for you, translating if necessary. Take a picture of a landmark, and it recognizes it. Take a picture of a logo, bookcover, or movie poster, and it searches for information about that graphic. Take a picture of a business card, and it offers to add the person&amp;#8217;s contact information to your address book (which in my case then syncs with Gmail and my desktop email client&amp;#8217;s address book). It isn&amp;#8217;t perfect, but what it already does is pretty amazing. For example, I was sitting in a ski lodge at Howelsen Hill, home of the US Ski Team (Jumping), surrounded by the flags of the various countries of the Olympics, and I wanted to know to which country a particular flag belonged. Google Goggles not only found the right country, but it linked me to the Wikipedia article about the country so I could read more about it.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Games with a Wiimote&lt;/strong&gt; &amp;#8211; Who said gaming for phones was restricted to onscreen controls? The Droid has an accelerometer built-in, as well as a D-Pad and a multitude of buttons for gaming. But the most fun (and probably battery-taxing) feature comes with the help of a Wiimote and the WiimoteControl application. As the Wiimote connects via bluetooth, and the phone has a bluetooth radio, the two can connect to each other. WiimoteControl makes the Wiimote look just like another input device, available for use by every application on the phone. Combine this with one of the popular games that support input customization, and the Wiimote turns the Droid into a gaming device full of fun. I do not play games much myself, so this is perfect to fill the occasional car ride on vacation, as I lack any other kind of portable gaming device.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; Client&lt;/strong&gt; &amp;#8211; I realize most people do not want a phone so they can use it as an &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; Client. Most people probably do not even know what &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt;, let alone why they would want it. That doesn&amp;#8217;t stop the Droid from having an awesome shell client, ConnectBot. This lets me connect to my server or desktop from anywhere I have cell service, which is just about anywhere. I run irssi on my server inside a &lt;span class=&quot;caps&quot;&gt;GNU&lt;/span&gt; Screen session, so this lets me keep up with the &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; chatter from anywhere. For those that want shell access to their local phone as well, ConnectBot allows you to open a local shell.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;FTP&lt;/span&gt; Server&lt;/strong&gt; &amp;#8211; The Droid supports local file access just by plugging the phone into the computer. But who wants to play with cables just to transfer a single picture? Enter SwiFTP, an &lt;span class=&quot;caps&quot;&gt;FTP&lt;/span&gt; server for Android. Fire up the application, start the server, and connect from any &lt;span class=&quot;caps&quot;&gt;FTP&lt;/span&gt; client to transfer files. It is not as fast as a &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; connection, but it is far more convenient.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt;&lt;/strong&gt; &amp;#8211; For awhile now, I have wanted a handheld &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; device for hiking, biking, skiing, etc. However, I usually could not justify the benefits of a &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; based on the cost of the devices on the market. However, now that I have my Droid, I no longer need a &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt;. Google My Tracks, another Google Labs product, records &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; tracks. It records your location at various, configurable time intervals, allowing export via standard &lt;span class=&quot;caps&quot;&gt;GPX&lt;/span&gt; files or upload to Google Maps. The application also shows graphs of speed and elevation vs time, various statistics such as max speed, and a map overlay of the route taken. It&amp;#8217;s perfect for telling me that I can take a ski run 1.2 miles long at 99.6 km/h, or showing the maximum gradient I took while riding my mountain bike. Want more information about the &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; satellites themselves? &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; Status tells you how many satellites are in view, in addition to accuracy information and a radar map showing marked waypoints. Finally, I should note that the camera application can record your location when taking a picture, which is pretty neat when the data is overlayed on a map after a trip. The usually gets a fix before I can frame the shot, so it&amp;#8217;s fast too.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Barcode Scanner&lt;/strong&gt; &amp;#8211; The Barcode Scanner and Google Shopper applications have to be my most unexpected use of my phone. Picture this: you are in your bookstore wondering if the store is charging far too much for a book. You whip out your phone, take a picture of the barcode on the book, and your phone returns a list of prices from various online retailers. These applications, which work well together, are quite handy. In addition, &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; and contact sharing is easy. Just take a picture of a barcode, which can even be generated by another phone, and the application will recognize the type and offers the appropriate actions.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Google Sky Map&lt;/strong&gt; &amp;#8211; This application has to be the most innovative use of my phone so far. Combine the phone&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt;, the phone&amp;#8217;s accelerometer, and a connection to a catalog of astronomy data, and you have Google Sky Map. Start up the application, point the phone at the night sky, and watch as constellations, stars, and planets are identified on the screen.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are just some of the reasons my Motorola Droid, and Android itself, are awesome. This isn&amp;#8217;t to say my Droid doesn&amp;#8217;t have its faults as well. It is not close to perfect. For example, when the phone is done charging, it immediately starts to drain the battery and refuses to charge until the power source is killed and then reconnected. Google Voice sometimes decides to not sync properly, resulting in issues. For some reason, the phone has both a Gmail client and an email client, two separate applications with similar feature sets (except for the fact the email client cannot move a message from one &lt;span class=&quot;caps&quot;&gt;IMAP&lt;/span&gt; folder to another). The same is true of the Corporate Calendar application and the Calendar application; the former connects to Exchange while the latter connects to Google Calendar and Google Tasks. Android fragmentation is indeed a problem as well. Many different phones run slightly different versions of Android, and carriers are slow to upgrade their devices, resulting in numerous devices unable to run the latest applications. Hopefully these issues are solved in the future.&lt;/p&gt;
&lt;p&gt;My phone is awesome; Android is awesome. Hopefully they&amp;#8217;ll get even better in the future.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Testing Whether an Integer is a Power of 2</title>
         <link>http://bvargo.com/2010/05/13/testing-whether-integer-power-2/</link>
         <pubDate>Thu, 13 May 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/05/13/testing-whether-integer-power-2/</guid>
         <description>
            &lt;p&gt;By using the &amp;amp; (logical and) operator, we can easily (and quickly!) test whether an integer is a power of 2.&lt;/p&gt;
&lt;p&gt;In C:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isPowerOfTwo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This works because an integer that is a power of two, x, is represented by a single 1 bit, with the other bits being 0. The same bit in x-1 will always be 0 because of the subtraction. Thus, when the two are anded together, the result will always be 0.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;x = 1: x = 0001, x-1 = 0000, x &amp;amp; x-1 = 0001 &amp;amp; 0000 = 0000&lt;/li&gt;
	&lt;li&gt;x = 2: x = 0010, x-1 = 0001, x &amp;amp; x-1 = 0010 &amp;amp; 0001 = 0000&lt;/li&gt;
	&lt;li&gt;x = 4: x = 0100, x-1 = 0011, x &amp;amp; x-1 = 0100 &amp;amp; 0011 = 0000&lt;/li&gt;
	&lt;li&gt;x = 8: x = 1000, x-1 = 0111, x &amp;amp; x-1 = 1000 &amp;amp; 0111 = 0000&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But if x is not a power of two, the result is not 0:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;y = 3: y = 0011, y-1 = 0010, y &amp;amp; y-1 = 0011 &amp;amp; 0010 = 0010&lt;/li&gt;
	&lt;li&gt;y = 5: y = 0101, y-1 = 0100, y &amp;amp; y-1 = 0101 &amp;amp; 0100 = 0100&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;br /&gt;
I have come across another way to quickly test if an integer is a power of two.&lt;/p&gt;
&lt;p&gt;In C:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isPowerOfTwo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;See if you can figure this one out for yourself.&lt;/p&gt;
         </description>
      </item>
      
      <item>
         <title>Hello World</title>
         <link>http://bvargo.com/2010/05/12/hello-world/</link>
         <pubDate>Wed, 12 May 2010 00:00:00 GMT></pubDate>
         <guid>http://bvargo.com/2010/05/12/hello-world/</guid>
         <description>
            &lt;p&gt;Hello and welcome to my blog.&lt;/p&gt;
         </description>
      </item>
      

   </channel>
</rss>
