<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3224008808345429390</id><updated>2012-01-23T16:52:36.973-05:00</updated><category term='Visual Studio'/><category term='MySQL'/><category term='Install Notes'/><category term='Predictions'/><category term='Language Design'/><category term='C'/><category term='CentOS'/><category term='Geolocation'/><category term='C#/.NET'/><category term='Perl'/><category term='General Programming'/><category term='Java'/><category term='OCaml/F#'/><category term='Prolog'/><category term='Refactoring'/><category term='PHP'/><category term='Shell'/><category term='Unicode'/><category term='Smalltalk'/><category term='Linux'/><category term='Projects'/><category term='Humor'/><category term='Ubuntu'/><category term='Rant'/><category term='Miscellaneous'/><category term='Virtualization'/><category term='JavaScript'/><category term='Paste Ninja'/><category term='Golang'/><title type='text'>Zaemis</title><subtitle type='html'>running my mouth off one blog post at a time</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>66</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-324408225064364270</id><published>2011-10-26T00:52:00.000-04:00</published><updated>2011-10-28T18:31:23.404-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>Please God, Give Me Something New!</title><content type='html'>"Here... check out this (link). But you have to use the most recent version of Chrome." Sigh. Haven't we been through this already? 15 years have passed and we're headed right back to the same place we started... "Best viewed in &amp;lt;someone's favorite browser&amp;gt;." It's sad, really.&lt;br /&gt;&lt;br /&gt;Don't get me wrong. Years of standardization work on HTML, JavaScript, the DOM, CSS, etc. cleaned up a lot of messy lose ends and yes it was indeed necessary, but stringent standardization also stifles creativity. And now that HTML5 and friends have loosened some of the restrictions the pendulum has started to swing back in the opposite direction. People have started to innovate again. This time around it's Firefox vs Chrome instead of Internet Explorer vs Netscape.&lt;br /&gt;&lt;br /&gt;There's a systemic problem that goes beyond browser wars, however. Remember AOL? This time it's Facebook trying to be “The Internet.” Remember mainframes and terminals? After pushing everything to the desktop, now we're pushing everything back “to the cloud.” All the fourth and fifth generation programming languages have come and gone and the best we have now is Java and Clojure?! Remember Ajax, er I mean DHTML, er I mean JavaScript? We're all "innovating" but nobody is really doing anything new, exciting, and unique.&lt;br /&gt;&lt;br /&gt;Hell, Tesla plugged 200 light bulbs into the ground and lit them up 25-miles away from a power source in 1899 and the best we have now is Solyndra and the Prius? What gives?!&lt;br /&gt;&lt;br /&gt;The sine-like cycle of technological advancements wouldn't be bad if each cycle actually gave us something new; you know, an &lt;i&gt;advancement&lt;/i&gt;. Maybe that's what has me so jaded. Each cycle seems to rehash the previous cycle and there's nothing really new and exciting anymore. We're moving in circles, not traveling in spirals. The more things change, the more they stay the same. Is Quindlen right, and every story has already been told?&lt;br /&gt;&lt;br /&gt;Think about HTML5's canvas element which everyone is saying how great and wonderful it is, an area for 2D drawing that can be manipulated with JavaScript. If browsers had actually implemented decent support for SVG 10 years ago we wouldn't need canvas now. That's right, we've had this “hot new technology” for 10 years already. And sadly, SVG is superior in many ways. And sadly, we've had 3D capability with VRML/X3D since the mid-90s. And sadly, we've settled for something less and are grinning from ear to ear. &lt;br /&gt;&lt;br /&gt;Wouldn't you like to have technology from 10 years into the future and have it now? It sounds tempting, but I'm not so sure I really would... because it'd probably be the same as what I've already had for the past 10 years just with a new marketing campaign.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-324408225064364270?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/324408225064364270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/10/please-god-give-me-something-new.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/324408225064364270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/324408225064364270'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/10/please-god-give-me-something-new.html' title='Please God, Give Me Something New!'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5167956127738170514</id><published>2011-09-18T00:43:00.003-04:00</published><updated>2011-09-18T03:06:19.361-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Top-10 PHP String Functions</title><content type='html'>&lt;p&gt;By day I work as a programmer at &lt;a href="http://www.shoregroup.com"&gt;ShoreGroup, Inc&lt;/a&gt;. By night I'm a freelance developer and now the managing editor for &lt;a href="http://www.sitepoint.com"&gt;SitePoint&lt;/a&gt;'s latest site, &lt;a href="http://www.phpmaster.com"&gt;PHPMaster.com&lt;/a&gt;. Helping out with the site has been pretty fun so far; my Australian counterparts are all pretty cool, and I've met some really great new authors too. If you haven't visited yet, take a moment and check out PHPMaster.com (there's still some wrinkles to iron out on the site, but we're working to identify and fix them all as soon as we can).&lt;/p&gt;&lt;p&gt;Part of my duties as a &lt;a href="http://www.wisegeek.com/what-does-a-managing-editor-do.htm"&gt;managing editor&lt;/a&gt; include working with authors to make sure the site's content is well balanced. PHPMaster.com is targeting PHP programmers of all skill levels, so there should be a good mix of basic, beginner, intermediate, and advanced content. Planning for a beginner article that demonstrates basic string handling functions, I wondered which function to highlight. I wanted to show ones that would be most relevant, not necessarily ones that were my favorite, so I decided to do some static analysis of popular open-source projects to find out which string functions were used the most. The results were surprising, so I thought I'd share my "research."&lt;/p&gt;&lt;p&gt;I used the source of a closed-source PHP project that I have access to and the following open-source (or open-source-ish) projects as code samples for the analysis:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://drupal.org/"&gt;Drupal&lt;/a&gt; (v7.x-dev)&lt;/li&gt;&lt;li&gt;&lt;a href="http://gallery.menalto.com/"&gt;Gallery&lt;/a&gt; (v3.0.2)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.joomla.org/"&gt;Joomla&lt;/a&gt; (v1.7.0-Stable-Full)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.magentocommerce.com/"&gt;Magento eCommerce&lt;/a&gt; (v1.6.1.0-alpha1)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.mediawiki.org/wiki/MediaWiki"&gt;MediaWiki&lt;/a&gt; (v1.17.0)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.oscommerce.com/"&gt;OSCommerce&lt;/a&gt; (v3.0.2)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.phpbb.com/"&gt;phpBB&lt;/a&gt; (v3.0.9)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.phpmyadmin.net/home_page/index.php"&gt;phpMyAdmin&lt;/a&gt; (master-20110914-022001)&lt;/li&gt;&lt;li&gt;&lt;a href="http://wordpress.org/"&gt;WordPress&lt;/a&gt; (nightly build, Sept. 14, 2011)&lt;/li&gt;&lt;li&gt;&lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt; (v1.11.9)&lt;/li&gt;&lt;li&gt;&lt;a href="http://jpgraph.net/"&gt;JpGraph&lt;/a&gt; (v3.0.7)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Then I ran the following PHP to tally the functions:&lt;/p&gt;&lt;pre&gt;#! /usr/bin/env php&lt;br /&gt;&amp;lt;?php&lt;br /&gt;if ($_SERVER["argc"] != 4) {&lt;br /&gt;    $script = basename(__FILE__);&lt;br /&gt;    fprintf(STDERR, "usage: %s directory max exts\n", $script);&lt;br /&gt;    fprintf(STDERR, "\tdirectory - directory to start traversal\n");&lt;br /&gt;    fprintf(STDERR, "\tmax - maximum number of results to return\n");&lt;br /&gt;    fprintf(STDERR, "\texts - comma-separated list of file extensions\n");&lt;br /&gt;    fprintf(STDERR, "example: %s /var/www 20 php,inc\n", $script);&lt;br /&gt;    exit(1);&lt;br /&gt;}&lt;br /&gt;// no error-checking... don't be stupid&lt;br /&gt;$directory = $_SERVER["argv"][1];&lt;br /&gt;$max = $_SERVER["argv"][2];&lt;br /&gt;$extsRegex = "/(" . str_replace(",", "|", $_SERVER["argv"][3]) . ')$/';&lt;br /&gt;&lt;br /&gt;$dirIter = new RecursiveDirectoryIterator($directory);&lt;br /&gt;$recIter = new RecursiveIteratorIterator($dirIter);&lt;br /&gt;$iter = new RegexIterator($recIter, $extsRegex);&lt;br /&gt;&lt;br /&gt;$funcs = array();&lt;br /&gt;foreach ($iter as $file) {&lt;br /&gt;    $tokens = token_get_all(file_get_contents($file));&lt;br /&gt;    foreach ($tokens as $t) {&lt;br /&gt;        if (is_array($t) &amp;amp;&amp;amp; $t[0] == T_STRING &amp;amp;&amp;amp; function_exists($t[1])) {&lt;br /&gt;            if (!isset($funcs[$t[1]])) {&lt;br /&gt;                $funcs[$t[1]] = 0;&lt;br /&gt;            }&lt;br /&gt;            $funcs[$t[1]]++;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;arsort($funcs);&lt;br /&gt;&lt;br /&gt;$max = min(count($funcs), $max);&lt;br /&gt;if ($max) {&lt;br /&gt;    list($funcs) = array_chunk($funcs, $max, true);&lt;br /&gt;}&lt;br /&gt;print_r($funcs);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I took the resulting list of functions and extracted the string-specific ones to come up with this top-10 list (sorted in decreasing order of most-used):&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;substr()&lt;/code&gt; - 6,605&lt;/li&gt;&lt;li&gt;&lt;code&gt;sprintf()&lt;/code&gt; - 5,604&lt;/li&gt;&lt;li&gt;&lt;code&gt;implode()&lt;/code&gt;/&lt;code&gt;join()&lt;/code&gt; - 4,829&lt;/li&gt;&lt;li&gt;&lt;code&gt;strlen()&lt;/code&gt; - 4,557&lt;/li&gt;&lt;li&gt;&lt;code&gt;chr()&lt;/code&gt; - 4,122&lt;/li&gt;&lt;li&gt;&lt;code&gt;str_replace()&lt;/code&gt; - 4,009&lt;/li&gt;&lt;li&gt;&lt;code&gt;explode()&lt;/code&gt; - 3,401&lt;/li&gt;&lt;li&gt;&lt;code&gt;strpos()&lt;/code&gt; - 3,238&lt;/li&gt;&lt;li&gt;&lt;code&gt;htmlspecialchars()&lt;/code&gt; - 3,171&lt;/li&gt;&lt;li&gt;&lt;code&gt;trim()&lt;/code&gt; - 2,998&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I expected functions like &lt;code&gt;substr()&lt;/code&gt; and &lt;code&gt;trim()&lt;/code&gt; to be on the list, but &lt;code&gt;chr()&lt;/code&gt; was a surprise. Before this I probably would have laughed at you if you told me &lt;code&gt;chr()&lt;/code&gt; is used almost twice as much as &lt;code&gt;strtolower()&lt;/code&gt; (which came in 12th place with 2,267). Interesting results indeed!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5167956127738170514?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5167956127738170514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/09/top-10-string-functions.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5167956127738170514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5167956127738170514'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/09/top-10-string-functions.html' title='Top-10 PHP String Functions'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-7351625532846229557</id><published>2011-07-10T00:48:00.000-04:00</published><updated>2011-07-10T00:48:50.055-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Avoid Fetch-Object Abuse</title><content type='html'>Lately I'm finding a lot of instances of the &lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; function being used in a particular codebase I help maintain. Unfortunately, I've yet to see it used correctly. It always seems to be used to retrieve a &lt;tt&gt;stdClass&lt;/tt&gt; object from a query result where &lt;tt&gt;mysql_fetch_array()&lt;/tt&gt; or &lt;tt&gt;mysql_fetch_assoc()&lt;/tt&gt; would be the more appropriate choice.&lt;br /&gt;&lt;pre&gt;$row = mysql_fetch_object($result);&lt;br /&gt;$kitten = new Kitten();&lt;br /&gt;$kitten-&gt;setName($row-&gt;name);&lt;br /&gt;$kitten-&gt;setColor($row-&gt;color);&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;Put aside the argument that the code should be using &lt;a href=" http://us.php.net/manual/en/book.pdo.php"&gt;PDO&lt;/a&gt; or the &lt;a href=" http://us3.php.net/manual/en/book.mysqli.php"&gt;MySQLi extension&lt;/a&gt; instead of the legacy MySQL extension. &lt;tt&gt;mysqli_result::fetch_object()&lt;/tt&gt; and &lt;tt&gt;PDOStatement::fetchObject()&lt;/tt&gt; have the same potential for abuse. The above code is wrong because the returned result is an object but treated like it's an array. &lt;br /&gt;&lt;br /&gt;The &lt;tt&gt;mysql_fetch_array()&lt;/tt&gt; and &lt;tt&gt;mysql_fetch_assoc()&lt;/tt&gt; functions are used to retrieve a row from the query's result set. I prefer to use &lt;tt&gt;mysql_fetch_assoc()&lt;/tt&gt; so I can access the values using column names.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;mysql_fetch_array()&lt;/tt&gt; - return an array corresponding to the fetched row and move the internal data pointer to the next. The array is indexed numerically if &lt;tt&gt;MYSQL_NUM&lt;/tt&gt; is specified, associatively if &lt;tt&gt;MYSQL_ASSOC&lt;/tt&gt; is specified, or both by default or if &lt;tt&gt;MYSQL_BOTH&lt;/tt&gt; is specified.&lt;/li&gt;&lt;li&gt;&lt;tt&gt;mysql_fetch_assoc()&lt;/tt&gt; - return an associative array corresponding to the fetched row and move the internal data pointer to the next. It is the same as calling &lt;tt&gt;mysql_fetch_array()&lt;/tt&gt; using &lt;tt&gt;MYSQL_ASSOC&lt;/tt&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; on the other hand was designed to create and populate an instance of an object using the row of data.&lt;br /&gt;&lt;pre&gt;$kitten = mysql_fetch_object($result, "Kitten");&lt;/pre&gt;If &lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; is called without the second argument, the name of the object type to create, then a &lt;tt&gt;stdClass&lt;/tt&gt; object is returned that has public properties named after the result columns to expose the data. There isn't any benefit to this over an array. It is just an object for the sake of having an object, and not a very useful object at that. Incidentally, an array can always be casted to a &lt;tt&gt;stdObject&lt;/tt&gt; later if, for some odd reason, it's needed:&lt;br /&gt;&lt;pre&gt;$obj = (object)$array;&lt;br /&gt;&lt;/pre&gt;An object is a data structure that encapsulates variables to maintain state and related functions to manipulate the state. A &lt;tt&gt;stdClass&lt;/tt&gt; data object just collects values and then exposes them as public properties. It does not observe proper encapsulation, there is no state, and there are no methods to interact with the object. It is no more than an array that uses object-syntax. My rule of thumb is: if you call &lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; without specifying a class name, you're "doing it wrong."&lt;br /&gt;&lt;br /&gt;A related point worth mentioning is even a good programmer may run into some difficulty when trying to use &lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; correctly since the function is intrinsically broken (though some will argue differently). The function first creates an instance of the specified class, then populates its internal variables, and lastly invokes the constructor. The purpose of a constructor is to initialize the object's values and resources, but since the constructor is called last the values set from the result row may be overwritten. The programmer must take this into account and guard against it if the objects might be instantiated by both &lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; and &lt;tt&gt;new&lt;/tt&gt;.&lt;br /&gt;&lt;pre&gt;class Kitten&lt;br /&gt;{&lt;br /&gt;    private $name;&lt;br /&gt;    private $color;&lt;br /&gt;    ...&lt;br /&gt;    public function __construct() {&lt;br /&gt;        if (!isset($this-&gt;name)) {&lt;br /&gt;            $this-&gt;name = "Unknown";&lt;br /&gt;        }&lt;br /&gt;        ...&lt;br /&gt;&lt;/pre&gt;If you're like me and have a large codebase with the misuse of &lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; deeply entangled throughout, it may not be practical to find and fix each instance. The best advice I can offer is to educate yourself and others how the function should be used so its abuse isn't perpetuated. Then, be cautious when using &lt;tt&gt;mysql_fetch_object()&lt;/tt&gt; correctly and understand the process it follows to create and return an object. If not for yourself, then do it for the kittens.&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;a href="https://lh4.googleusercontent.com/-yIkyAaj54T8/ThktcxJTNSI/AAAAAAAAAT0/kWfFPgYIbsA/kills-kittens.jpg"&gt;&lt;img src="https://lh4.googleusercontent.com/-yIkyAaj54T8/ThktcxJTNSI/AAAAAAAAAT0/kWfFPgYIbsA/kills-kittens.jpg" style="width: 400px;" /&gt;&lt;/a&gt;&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-7351625532846229557?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/7351625532846229557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/07/avoid-fetch-object-abuse.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7351625532846229557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7351625532846229557'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/07/avoid-fetch-object-abuse.html' title='Avoid Fetch-Object Abuse'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh4.googleusercontent.com/-yIkyAaj54T8/ThktcxJTNSI/AAAAAAAAAT0/kWfFPgYIbsA/s72-c/kills-kittens.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2300604535190748808</id><published>2011-07-04T09:00:00.005-04:00</published><updated>2011-07-10T02:06:00.628-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 10 - Conclusions</title><content type='html'>So here I am, more than 20 hours with Smalltalk and 10 blog posts about my experiences as required by the terms of &lt;a href="http://www.blog.ghost-network.net/2011/06/the-challenge-learning-ocaml-first-2-hours/"&gt;my challenge&lt;/a&gt;. Josh said he chose Smalltalk for me because of the language's history of helping giving rise to object-oriented programming, which he thinks I hate. (For the record I don't hate OO; I hate the awkwardness and complexity its over-zealous application inflicts.) But I think secretly he was hoping it would endear me to Java in the same way as I was hoping OCaml would help him see past Java. Smalltalk gave me a newfound respect, not for OO, but for the language's innovations and lasting influence. If anything in relation to current-day OO practices, my experience confirmed how botched OO adoption has been given what it was intended to be. Regardless, while I don't think I'll be using Smalltalk in the foreseeable future, it was definitely fun to explore and gave me a lot of things to think about.&lt;br /&gt;&lt;br /&gt;Smalltalk isn't a popular "mainstream" language like Java or PHP, but it was highly influential on many of them. It's a language that hasn't been afraid to try bold, new ideas. Other languages adopted its innovations; some did so successfully, others not so much. Will new innovations from Smalltalk and its community be just as influential in the future? I can't help but think that if Squeak has successfully abandoned the MVC architecture in favor of Morphic, maybe the days of MVC web frameworks such as Struts, Zend Framework, and Rails are numbered.&lt;br /&gt;&lt;br /&gt;Message passing is a key concept in Smalltalk and provides the flexibility of duck typing. But late/dynamic binding prohibits many compiler-time optimizations that could otherwise be performed on statically-compiled code. Is there continued benefit to such an approach now that we're inundated with so many dynamic languages that have (or at least seem to emulate reasonably well) direct invocation, and thus better performance, such as Lua and JavaScript? Perhaps a greater benefit could be realized if message passing was handled asynchronously.&lt;br /&gt;&lt;br /&gt;In Smalltalk, everything is an object. Even basic language constructs such as if-statements and while loops have been distilled down to objects and message passing. I respect Kay for intentionally taking an extreme position to force new ways of looking at things, though I believe the "everything is a" mindset can lead to awkward perceptions. The human mind is adept at categorizing things into different classifications exactly because not everything is the same. Ruby claims everything is an object too, which is misleading because it still has basic language constructs. I wonder where the sweet spot between abstraction and reality is, and in what ways can programming languages more accurately reflect how we view the world so we don't end up with with shimmed, over-architectured, &lt;a href="http://zaemis.blogspot.com/2011/05/spaghetti-code-considered-harmful.html"&gt;spaghetti code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Overall I found the core concepts of Smalltalk pretty easy to learn (since there are so few), and it was fun to write Smalltalk code and explore objects and Morphs in Squeak's environment. I encourage others who may not be familiar with Smalltalk to spend a little time with it as I did. I can't say it made me a better programmer, but in some sense it made me a better person because I now have a better understanding of history and a lot of things to think about.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2300604535190748808?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2300604535190748808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-10-conclusions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2300604535190748808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2300604535190748808'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-10-conclusions.html' title='Smalltalk Challenge: Post 10 - Conclusions'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-4439293609854139611</id><published>2011-07-03T09:00:00.006-04:00</published><updated>2011-07-10T02:06:00.629-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 9 - Koans</title><content type='html'>Besides tinkering with turtles and hashes in Squeak, I secretly went back to GNU Smalltalk and went through some of the &lt;a href="https://github.com/sl4m/gnu_smalltalk_koans"&gt;Smalltalk Koans&lt;/a&gt;. Sssh... don't tell Josh!&lt;br /&gt;&lt;br /&gt;Programming koans are a series of failing unit tests that a student reads through and corrects. Each test demonstrates a particular concept in the language. They can be a fun way to review one's understanding of a language, and occasionally learn something new. Here's an of a koan:&lt;br /&gt;&lt;pre&gt;testSingleCharacterFromString [&lt;br /&gt;    | string |&lt;br /&gt;&lt;br /&gt;    string := 'Smalltalk'.&lt;br /&gt;&lt;br /&gt;    self expect: (self fillMeIn) toEqual: (string at: 1).&lt;br /&gt;    self expect: (self fillMeIn) toEqual: (string at: 6).&lt;br /&gt;]&lt;/pre&gt;When the test suite is run, it displays:&lt;br /&gt;&lt;pre&gt;Do not lose hope.  Expected value should equal actual value.&lt;br /&gt;&lt;br /&gt;Expected : FILL ME IN&lt;br /&gt;Actual   : $S  (an instance of Character)&lt;br /&gt;&lt;br /&gt;TestString#testSingleCharacterFromString has damaged your karma&lt;br /&gt;(in src/koans/TestString.st)&lt;/pre&gt;The name of the method indicates it is possible access the characters that make up a string. The test shows how the &lt;tt&gt;at:&lt;/tt&gt; message is passed to a string to obtain a character at the given index. The programmer must replace &lt;tt&gt;(self fillMeIn)&lt;/tt&gt; with the correct value which will allow the test to pass and the student to proceed.&lt;br /&gt;&lt;pre&gt;self expect: $S toEqual: (string at: 1).&lt;br /&gt;self expect: $t toEqual: (string at: 6).&lt;/pre&gt;This demonstrates that in Smalltalk character instances are preceded by a dollar-sign, and indexes start at 1, not 0 as in many other languages.&lt;br /&gt;&lt;br /&gt;Going through the koans, I thought the ones from &lt;tt&gt;TestString.st&lt;/tt&gt;, &lt;tt&gt;TestMessage.st&lt;/tt&gt;, and &lt;tt&gt;TestDictionary.st&lt;/tt&gt; were exceptionally good. My favorite was this one from &lt;tt&gt;TestMessage.st&lt;/tt&gt;, which demonstrates an unintuitive edge-case resulting from Smalltalk's &lt;a href="http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-3-awkward.html"&gt;everything-is-an-object&lt;/a&gt; and &lt;a href="http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-5-talking-to.html"&gt;message passing&lt;/a&gt; philosophies.&lt;br /&gt;&lt;pre&gt;testMessageCascading [&lt;br /&gt;    | value |&lt;br /&gt;&lt;br /&gt;    value := 3 + 2; * 100.  "';' separates each message sent to '3'"&lt;br /&gt;&lt;br /&gt;    self expect: (self fillMeIn) toEqual: value.&lt;br /&gt;&lt;br /&gt;    "Think about it: we are sending multiple messages to '3'."&lt;br /&gt;]&lt;/pre&gt;The correct answer is 300. Pretty evil, eh?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-4439293609854139611?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/4439293609854139611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-9-koans.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4439293609854139611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4439293609854139611'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-9-koans.html' title='Smalltalk Challenge: Post 9 - Koans'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8466264584073053610</id><published>2011-07-02T09:00:00.009-04:00</published><updated>2011-07-10T02:06:00.630-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 8 - Virtual Images</title><content type='html'>Virtualization is in vogue right now as companies use such technology to run multiple systems on consolidated hardware. Remember, Smalltalk was designed as a language &lt;em&gt;and&lt;/em&gt; an environment. No one is about to replace Windows (or Ubuntu, though I'm tempted) with Smalltalk as their operating system, so it makes sense for it to be implemented as a virtual machine.&lt;br /&gt;&lt;br /&gt;Similar to products like VMWare Workstation or VirtualBox, most Smalltalk implementations consist of a Virtual machine (VM) application and an image file. The image file contains the definition and state of the Smalltalk environment which is realized by the VM. It may be helpful to think about the image file as a program saved somewhere on your computer's hard drive, and the VM is your computer's processor that executes the code to do something useful.&lt;br /&gt;&lt;br /&gt;A Squeak installation consists of four files: a VM executable and three files that make up the image.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The VM is the interpretor that "runs" a Smalltalk image.&lt;/li&gt;&lt;li&gt;The &lt;tt&gt;.sources&lt;/tt&gt; file contains the core Squeak system and base libraries.&lt;/li&gt;&lt;li&gt;The &lt;tt&gt;.image&lt;/tt&gt; file contains the current state of the running system.&lt;/li&gt;&lt;li&gt;The &lt;tt&gt;.changes&lt;/tt&gt; file is contains a log of changes made to the system.&lt;/li&gt;&lt;/ul&gt;You can save the state of the environment at any time while working in Squeak, which is stored between the &lt;tt&gt;.image&lt;/tt&gt; and &lt;tt&gt;.changes&lt;/tt&gt; files. Such snapshots can be loaded later to go back to previous sessions, or shared with others as a means of distribution.&lt;br /&gt;&lt;br /&gt;As with most things in life there are advantages and disadvantages with image-based imperative programming. Apparently though the disadvantages outweigh the advantages. The latest standardization attempt of Smalltalk, ANSI/INCITS 319 1998 (ANSI Smalltalk), does away with the old model and specifies a fully declarative model for writing Smalltalk programs. Some reasons for adopting the new model were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Programs could be inaccessible if the image becomes out dated or corrupted.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Because the same image is used for development and production, is makes it very difficult to support situations where the development and target execution environments must be different (security restrictions, for example).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I did a quick screen recording to show what writing code in the environment is like. In Squeak, the programmer writes the code for a class and its methods directly in the System Browser window. At the top of the window are selection lists; from left to right, they list class categories, classes, method categories, and methods. Below them is a text area where the code is typed and saved. When the code is saved, Squeak automatically compiles it and makes it available to the rest of the system.&lt;br /&gt;&lt;br /&gt;&lt;iframe width="425" height="349" src="http://www.youtube.com/embed/foe6XHhoWy4" frameborder="0" allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8466264584073053610?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8466264584073053610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-8-virtual.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8466264584073053610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8466264584073053610'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-8-virtual.html' title='Smalltalk Challenge: Post 8 - Virtual Images'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/foe6XHhoWy4/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8927671680532560826</id><published>2011-07-01T09:00:00.011-04:00</published><updated>2011-07-10T02:06:00.631-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 7 - Turtles Ahoy!</title><content type='html'>I can remember going down to the computer lab while in grade school and &lt;a href="http://logo.twentygototen.org/ymbBJ9VB"&gt;using Logo&lt;/a&gt; on the then state-of-the-art Apple IIe computers. Supposedly Logo allowed students to explore mathematics in a tangible way, but I don't remember doing much more than drawing shapes by moving the little "turtle" around on the green screen and I still don't have much confidence in my math skills 20 years later. I don't think Logo helped kindle my interest in computers, either; games like &lt;a href="http://en.wikipedia.org/wiki/The_Oregon_Trail_%28video_game%29"&gt;The Oregon Trail&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Where_in_the_World_Is_Carmen_Sandiego%3F"&gt;Where in the World is Carmen Sandiego&lt;/a&gt; and the Commodore 64 computer were far more influential to me. But drawing little green triangles and squares was fun. And while Logo may not have been as influential in my education as Papert would have hoped, it was extremely influential to Smalltalk. In fact, the graphics &lt;tt&gt;Pen&lt;/tt&gt; object is actually very similar to Logo's turtle.&lt;br /&gt;&lt;br /&gt;The &lt;tt&gt;Pen&lt;/tt&gt; class is used for drawing. It inherits from &lt;tt&gt;BitBlt&lt;/tt&gt; which allows it to perform raster drawing on any form its bound to. The World is a form itself, so a pen bound to it will appear to draw on top of other windows and elements! The following example draws an octagonal-spiral on top of anything that's visible in the environment, centered around the point of a mouse click:&lt;br /&gt;&lt;pre&gt;pen := Pen new.&lt;br /&gt;    pen roundNib: 8;&lt;br /&gt;    color: Color random;&lt;br /&gt;(Sensor waitButton; redButtonPressed)&lt;br /&gt;    ifTrue: [&lt;br /&gt;            pen up;&lt;br /&gt;            goto: Sensor mousePoint;&lt;br /&gt;            down.&lt;br /&gt;        x := 1.&lt;br /&gt;        10 timesRepeat: [&lt;br /&gt;            4 timesRepeat: [pen go: 10 * x; turn: 45].&lt;br /&gt;            x := x + 2]].&lt;/pre&gt;&lt;img src="https://lh6.googleusercontent.com/-wR6rNl6vTjM/TgbLwJK7voI/AAAAAAAAARQ/m2zekwm2bhE/s800/squeak-8.png" width="425" /&gt;&lt;br /&gt;&lt;br /&gt;A new &lt;tt&gt;Pen&lt;/tt&gt; instance is created, the size of the line it draws is set to 8px by  the &lt;tt&gt;roundNib:&lt;/tt&gt; message (what better thickenss to draw octagons with?), and the color of the pen's line is randomly set by the &lt;tt&gt;color:&lt;/tt&gt; message.&lt;br /&gt;&lt;br /&gt;Sending a &lt;tt&gt;down&lt;/tt&gt; message is like placing a pen against a sheet of paper. When the pen is against the paper and is moved, a line is drawn. There is also the &lt;tt&gt;up&lt;/tt&gt; message which is like lifting the pen up away from the paper so it can be repositioned without making any marks.&lt;br /&gt;&lt;br /&gt;The pen is moved about the screen using the &lt;tt&gt;goto:&lt;/tt&gt;, &lt;tt&gt;go:&lt;/tt&gt; and &lt;tt&gt;turn:&lt;/tt&gt; messages. Like its Logo progenitor, the pen object responds to messages relative to its current position and direction. When asked to move 10px, the pen moves forward in which ever direction it's pointing in. Turning the pen 45 degrees and moving another 10px would result in a 45&amp;deg; angle drawn. The direction of the pen's motion can also be set with &lt;tt&gt;north&lt;/tt&gt;, &lt;tt&gt;east&lt;/tt&gt;, &lt;tt&gt;west&lt;/tt&gt;, &lt;tt&gt;south&lt;/tt&gt;, and &lt;tt&gt;direction&lt;/tt&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8927671680532560826?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8927671680532560826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-7-turtles-ahoy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8927671680532560826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8927671680532560826'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/07/smalltalk-challenge-post-7-turtles-ahoy.html' title='Smalltalk Challenge: Post 7 - Turtles Ahoy!'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh6.googleusercontent.com/-wR6rNl6vTjM/TgbLwJK7voI/AAAAAAAAARQ/m2zekwm2bhE/s72-c/squeak-8.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6172897000748560756</id><published>2011-06-30T09:00:00.006-04:00</published><updated>2011-07-10T02:06:00.631-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 6 - Morphic</title><content type='html'>As the Dynabook/Smalltalk environment was the first to introduce the windowed user interface, it's no surprise that the Model View Controller (MVC) pattern also made its first appearance in Smalltalk. In Smalltalk, the term "MVC" refers to both the architecture pattern that separates code responsibilities into model, view, and controller objects, and the user interface framework used to develop visual and interactive elements. The MVC framework manages objects in the environment using the MVC pattern.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Model objects are responsible for maintaining the behavior and state of the element.&lt;/li&gt;&lt;li&gt;View objects are responsible for the representation or appearance of the element within the world.&lt;/li&gt;&lt;li&gt;Controller objects are responsible for accepting user input and passing messages to the model and view objects.&lt;/li&gt;&lt;/ul&gt;But because of the complexity and limitations of the MVC architecture, Squeak has replaced the MVC framework with Morphic, a direct-manipulation user interface toolkit. Unlike MVC, Morphic didn't originate with Smalltalk. Rather, it was written by Randy Smith and John Maloney for Self, another OO programming language influenced by Smalltalk, and ported to Squeak by Maloney who is also one of the core Squeak developers.&lt;br /&gt;&lt;br /&gt;All interactive elements that exist within the environment in Morphic are subclasses of &lt;tt&gt;Morph&lt;/tt&gt;, and the majority of code that would normally be required by MVC is encapsulated in the &lt;tt&gt;Morph&lt;/tt&gt; class. For example:&lt;br /&gt;&lt;pre&gt;Morph new openInWorld.&lt;/pre&gt;will open a blue rectangle that you can move about the screen, resize, rotate, and more. When a custom morph extends &lt;tt&gt;Morph&lt;/tt&gt;, it inherits all of its parent's functionality and the programmer is freed to focus on customizing the morph instead of writing boiler-plate code. As Maloney wrote in &lt;a href="http://stephane.ducasse.free.fr/FreeBooks/CollectiveNBlueBook/morphic.final.pdf"&gt;An Introduction to Morphic&lt;/a&gt;, "In morphic, a little code goes a long way, and there is hardly any wasted effort."&lt;br /&gt;&lt;br /&gt;I actually took advantage of Morphic in my Kember Identity search code, though it's not something one might think of as requiring a manipulatable object. The &lt;tt&gt;step&lt;/tt&gt; message is intended for creating animations and morphs that update themselves dynamically over time (adding &lt;em&gt;liveness&lt;/em&gt; to the interface). Morphic repeatedly sends &lt;tt&gt;step&lt;/tt&gt; messages to each morph which may respond by executing their &lt;tt&gt;step&lt;/tt&gt; method (the rate at which &lt;tt&gt;step&lt;/tt&gt; messages are sent to an object can be specified by responding to the &lt;tt&gt;stepTime&lt;/tt&gt; message, but by default I believe it's set for every few milliseconds or so). The method actions run concurrently with whatever else is happening in the rest of the environment. This builtin threading was exactly what I needed to ensure the rest of the system remained responsive to the user while the code was searching for a hash that exhibits the Kember Identity.&lt;br /&gt;&lt;br /&gt;I subclassed the &lt;tt&gt;TextMorph&lt;/tt&gt; class and supplied the following &lt;tt&gt;step&lt;/tt&gt; method:&lt;br /&gt;&lt;pre&gt;Kember &amp;raquo; step&lt;br /&gt;    found | (currHash = stopHash)&lt;br /&gt;        ifFalse: [self contents: 'Testing ' , currHash.&lt;br /&gt;            found := self test: currHash.&lt;br /&gt;                found ifTrue: [self contents: 'Found '&lt;br /&gt;                        , currHash , '!'].&lt;br /&gt;            currHash := self nextHash: currHash.&lt;br /&gt;            currHash = stopHash&lt;br /&gt;                ifTrue: [self contents: 'KI was not found.']].&lt;/pre&gt;The &lt;tt&gt;contents:&lt;/tt&gt; method is inherited from &lt;tt&gt;TextMorph&lt;/tt&gt; to set the displayed text string, and the rest are instance variables and methods specific to my &lt;tt&gt;Kember&lt;/tt&gt; class.&lt;br /&gt;&lt;br /&gt;Morphs can respond to several other messages sent by the framework, too. Responding to the &lt;tt&gt;drawOn:&lt;/tt&gt;message allows a morph to customize its appearance, or how it "draws" itself in the environment. Responding to &lt;tt&gt;mouseDown:&lt;/tt&gt;, &lt;tt&gt;mouseUp:&lt;/tt&gt;, &lt;tt&gt;mouseMove:&lt;/tt&gt;, and &lt;tt&gt;keyStroke:&lt;/tt&gt; events lets the morph interact with the user's mouse and keyboard activities.&lt;br /&gt;&lt;br /&gt;Well that's 6 posts down now and only 4 more to go before I complete my challenge!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6172897000748560756?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6172897000748560756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-6-morphic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6172897000748560756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6172897000748560756'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-6-morphic.html' title='Smalltalk Challenge: Post 6 - Morphic'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8629063128978104490</id><published>2011-06-29T09:00:00.006-04:00</published><updated>2011-07-10T02:06:00.632-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 5 - Talking to Objects</title><content type='html'>Everything I've read about Smalltalk makes an effort to stress objects are capable of doing three things: maintaining state, receiving messages, and sending messages. The understanding that an object can maintains its own state is common across many languages, but message passing may be unfamiliar to programmers working with other languages (though message passing does play an important role in Objective-C). &lt;a href="http://c2.com/cgi/wiki?AlanKayOnMessaging"&gt;Alan Kay has said&lt;/a&gt; that message passing is the most important concept to understand in Smalltalk, and that objects have been over-emphasized.&lt;br /&gt;&lt;br /&gt;Smalltalk's object model follows the classical (class-based) style; the programmer writes a class which is then used by the runtime as a blueprint for instantiating an object. But unlike C++ or Java, the programmer never works with objects by invoking their methods directly in Smalltalk. Instead, messages are sent to the object which receives a message, looks up the appropriate method to perform, and then executes the method. This is more than a conceptual difference; it's a concrete implementation detail as explained by the following quote from Wikipedia's &lt;a href="http://en.wikipedia.org/wiki/Objective-C#Messages"&gt;Objective-C article&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;In a Simula-style language [like C++, Java, etc.], the method name is in most cases bound to a section of code in the target class by the compiler. In Smalltalk and Objective-C, the target of a message is resolved at runtime, with the receiving object itself interpreting the message. &lt;/blockquote&gt;Perhaps a suitable way of looking at it is that all of the properties and methods of an object are private. The only way to interact with the object is by sending it the appropriate messages.&lt;br /&gt;&lt;br /&gt;There are three types of messages in Smalltalk: unary messages that take no arguments, binary messages which have one argument, and keyword messages that can take one or more arguments.&lt;br /&gt;&lt;br /&gt;Unary messages appear after the object instance they're sent to. The &lt;tt&gt;cr&lt;/tt&gt; message is an example of a unary message that can be sent to a &lt;tt&gt;Transcript&lt;/tt&gt; object, which responds by displaying a newline character.&lt;br /&gt;&lt;pre&gt;Transcript cr.&lt;/pre&gt;Binary messages appear with an argument. For example, the binary message &lt;tt&gt;=&lt;/tt&gt; can be sent to &lt;tt&gt;foo&lt;/tt&gt; with the argument 42, and &lt;tt&gt;foo&lt;/tt&gt; responds by comparing its value with the argument and returning a &lt;tt&gt;Boolean&lt;/tt&gt; object set to whether the values were equal.&lt;br /&gt;&lt;pre&gt;foo = 42.&lt;/pre&gt;Keyword messages end with a colon and can take multiple arguments. The &lt;tt&gt;at:put:&lt;/tt&gt; message is an example of a keyword message which can be sent to an &lt;tt&gt;IntegerArray&lt;/tt&gt; object. The array responds by placing the value 42 at index 5.&lt;br /&gt;&lt;pre&gt;anIntegerArray at: 5 put: 42.&lt;/pre&gt;Keyword messages are a single message. That is, &lt;tt&gt;at:put&lt;/tt&gt; is not an &lt;tt&gt;at:&lt;/tt&gt; message followed by a &lt;tt&gt;put:&lt;/tt&gt; message. In Java, it might be written like &lt;tt&gt;&lt;nobr&gt;anIntegerArray.atPut(5, 42)&lt;/nobr&gt;&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;In statements that contain multiple messages, the order of precedence is from left to right with unary messages being sent first, then binary messages, and finally keyword messages, though the order can be influenced by parenthesis. Recall the example &lt;tt&gt;&lt;nobr&gt;2 + 1 / 4&lt;/nobr&gt;&lt;/tt&gt; from &lt;a href="http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-3-awkward.html"&gt;Post 3&lt;/a&gt;. The expression contains two binary operators, &lt;tt&gt;+&lt;/tt&gt; and &lt;tt&gt;/&lt;/tt&gt;. Following the precedence rules, &lt;tt&gt;2&lt;/tt&gt; is sent the message &lt;tt&gt;+&lt;/tt&gt; with the argument &lt;tt&gt;1&lt;/tt&gt; and then the message &lt;tt&gt;/&lt;/tt&gt; with the argument &lt;tt&gt;4&lt;/tt&gt;. Contrast this with how the statement would be evaluated in Java following the mathematical order of operations. To force that execution in Smalltalk, the expression would need to be parenthesized as &lt;tt&gt;&lt;nobr&gt;2 + (1 / 4)&lt;/nobr&gt;&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;It seems the biggest benefit of the approach is that its late/dynamic binding affords the flexibility of duck typing in a compiled language... but now that dynamic languages are widely used, and something like an inferred typing system can give the "feel" of dynamic programming in a strongly-typed language, I wonder if this is only historically important now. There is a runtime performance hit since method lookups happens at execution instead of compilation, and some Smalltalk implementations have explored method caching to help mitigate the impact, but it seems there must be a whole class of compile-time optimizations that cannot be performed by the compiler that may could affect performance as well.&lt;br /&gt;&lt;br /&gt;I asked about the advantages and drawbacks of message passing on the &lt;a href="https://groups.google.com/forum/#!topic/pilud/axLeziybRYw/discussion"&gt;PiLuD mailing list&lt;/a&gt;. Some of the respondents made pretty good points, and I recommend reading the exchange if you're interested in hearing some other opinions from a language-design perspective.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8629063128978104490?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8629063128978104490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-5-talking-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8629063128978104490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8629063128978104490'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-5-talking-to.html' title='Smalltalk Challenge: Post 5 - Talking to Objects'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5974593655942246709</id><published>2011-06-28T09:00:00.005-04:00</published><updated>2011-07-10T02:06:00.633-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 4 - Porting the Kember Identity</title><content type='html'>There are a few things I find myself tripping up over even after spending some time writing "meaningful" Smalltalk code, like using single quotes to delimit strings (double quotes are used for comments) and remembering the order in which different messages are sent, but the more code I write the easier it is to remember such things. After only a few hours, Smalltalk is still something new and unfamiliar.&lt;br /&gt;&lt;br /&gt;The first programs I wrote when &lt;a href="http://zaemis.blogspot.com/2010/11/week-with-golang-day-1.html"&gt;looking into Go&lt;/a&gt; were solutions to the first two &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; problems and a port of the &lt;a href="http://zaemis.blogspot.com/2009/06/kember-identity.html"&gt;Kember Identity&lt;/a&gt; search program. I decided to skip the Euler problems this time and go straight to the Kember Identity port.&lt;br /&gt;&lt;br /&gt;The Kember program ultimately boils down to generating and checking MD5 hashes. I didn't find any helpful cryptography related objects or methods in the default image, so I searched Google and eventually found Ron Teitelbaum's &lt;a href="http://www.squeaksource.com/Cryptography.html"&gt;Cryptography/Team package&lt;/a&gt;. Squeak uses a package management system called &lt;a href="http://wiki.squeak.org/squeak/1287"&gt;Monticello&lt;/a&gt; to load code into the image, so getting and installing the package was pretty easy. I copied and pasted the package repository's connection information into the Monticello Browser and loaded Rob Withers' contribution, Cryptography-rww.15.mcz.&lt;br /&gt;&lt;br /&gt;Once the package was loaded, I was able to obtain hashes with &lt;nobr&gt;&lt;tt&gt;MD5 &amp;raquo; hashStream:&lt;/tt&gt;&lt;/nobr&gt;, but the returned object was a &lt;tt&gt;ByteArray&lt;/tt&gt; and I needed to interpret it as a 32-character hexadecimal string. At first I took this approach to convert the array to a hex string:&lt;br /&gt;&lt;pre&gt;Kember &amp;raquo; md5: aString&lt;br /&gt;    "return 32-char MD5 hash of the given text" &lt;br /&gt;    | hash str |&lt;br /&gt;    hash := MD5 new&lt;br /&gt;                hashStream: (ReadStream on: aString).&lt;br /&gt;    str := ''.&lt;br /&gt;    1 to: hash size do: [:i | &lt;br /&gt;        str := str, ((hash at: i) radix: 16)].&lt;br /&gt;    &amp;uarr; str.&lt;/pre&gt;… only to find out later that objects of the &lt;tt&gt;ByteArray&lt;/tt&gt; class were modified by the cryptography package to accept a &lt;tt&gt;hex&lt;/tt&gt; message and will do the conversion for me. Oops! All the bit twiddling I had done could easily be replaced with:&lt;br /&gt;&lt;pre&gt;&amp;nbsp; &amp;nbsp; &amp;uarr; (MD5 new hashStream: (ReadStream on: aString)) hex.&lt;/pre&gt;Converting between hash representations wasn't the only part of the program I initially over-programmed. I was also doing long-form addition to obtain the next hash value in the sequence when all I really needed was a little bit of type juggling and string padding:&lt;br /&gt;&lt;pre&gt;Kember &amp;raquo; nextHash: aHashStr&lt;br /&gt;    "increment the MD5 hash"&lt;br /&gt;    | hexHash zeroes |&lt;br /&gt;    zeroes = '00000000000000000000000000000000'.&lt;br /&gt;    hexHash := ((ByteArray fromHexString: aHashStr)&lt;br /&gt;        asInteger + 1) asByteArray hex.&lt;br /&gt;    hexHash size &lt; 32&lt;br /&gt;        ifTrue: [&amp;uarr; (zeroes copyFrom: 1 to 32 - hexHash size)&lt;br /&gt;            , hexHash].&lt;br /&gt;    &amp;uarr; hexHash.&lt;/pre&gt;I guess it just proves the &lt;a href="http://www.c2.com/cgi/wiki?SmalltalkTutorial"&gt;saying is true&lt;/a&gt;, "learning the libraries is the 20% of learning a new language that takes 80% of the time and effort." If anything, at least I can take comfort in knowing I'm not the first person to over-program a solution while learning a new language.For those that want to check out my Kember code, I've set up my own repository and uploaded a Monticello package to &lt;a href="http://www.squeaksource.com/Zaemis.html"&gt;SqueakSource&lt;/a&gt;, and a file dump to &lt;a href="https://github.com/tboronczyk/Smalltalk-Experiments"&gt;Github&lt;/a&gt; (I suggest looking at it in raw mode if you go to Github because their Markdown chokes and truncates the pretty-print view).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5974593655942246709?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5974593655942246709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-4-porting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5974593655942246709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5974593655942246709'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-4-porting.html' title='Smalltalk Challenge: Post 4 - Porting the Kember Identity'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-7146063544492430921</id><published>2011-06-27T09:00:00.006-04:00</published><updated>2011-07-10T02:06:00.633-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 3 - Awkward</title><content type='html'>After spending a short time in the Smalltalk (Squeak) environment, it's easy to understand how other existing languages at the time were not suited for realizing the full potential of the Dynabook. Working in a visual environment is a far-cry from working at a mainframe terminal. It's ironic though that some of the same issues that plague OO now are the same that held Smalltalk back in the 80's... it consumed a substantial amount of memory and the performance was &lt;a href="www.heinzi.at/texte/smalltalk.pdf"&gt;not always optimal&lt;/a&gt;. For me, one of the issues is the awkwardness of Smalltalk's "everything is an object" philosophy.&lt;br /&gt;&lt;br /&gt;I believe the "everything is a ___" mindset causes problems, regardless of what fills in the blank. In TCL, everything is a string. In LISP, everything is a list. In Smalltalk, everything is an object. The fact of the matter is not everything in the world is homogeneous. Some things are objects, others are numbers, and yet others are actions. Forcing everything into the same conceptual model forces the programmer to perform cognitive acrobatics.&lt;br /&gt;&lt;br /&gt;Understanding the semantics behind a simple statement such as &lt;tt&gt;Transcript show: 'Hello World!'&lt;/tt&gt; is easy; a &lt;tt&gt;Transcript&lt;/tt&gt; window object is sent the message &lt;tt&gt;show:&lt;/tt&gt;, which then responds by displaying the argument. But the semantics behind conditional code execution isn't so intuitive. Smalltalk doesn't have a dedicated if-construct, instead conditional execution is achieved by passing messages to &lt;tt&gt;Boolean&lt;/tt&gt; objects, like so:&lt;br /&gt;&lt;pre&gt;x &amp;gt; 0&lt;br /&gt;    ifTrue: [Transcript show: 'Positive']&lt;br /&gt;    ifFalse: [Transcript show 'Negative'].&lt;/pre&gt;The object represented by the variable &lt;tt&gt;x&lt;/tt&gt; is sent the &lt;tt&gt;&amp;gt;&lt;/tt&gt; message with the argument &lt;tt&gt;0&lt;/tt&gt;. &lt;tt&gt;x&lt;/tt&gt; then compares its value with that of the argument and returns a &lt;tt&gt;Boolean&lt;/tt&gt; object in response. If the value of &lt;tt&gt;x&lt;/tt&gt; is a positive number then the resulting truth value of the returned object is true, otherwise the value is false. The &lt;tt&gt;ifTrue:ifFalse:&lt;/tt&gt; message is sent to the implicit &lt;tt&gt;Boolean&lt;/tt&gt; object providing two code block (which are also objects!) as arguments. All basic language constructs such as if-statements and while loops are abstracted as objects! While it does produce an appreciable amount of elegance and flexibility in the language, this thinking takes some getting used to.&lt;br /&gt;&lt;br /&gt;There's a lot going on behind the scenes with an expression like &lt;tt&gt;2 + 1 / 4&lt;/tt&gt; as well. A language like C will follow the rules of precedence stated by the mathematical order of operations. First 1 is divided by 4 which yields .25, and then 2 is added to .25 resulting in the final value 2.25. In Smalltalk, everything is an object which the programmer interacts with by sending messages. The literals &lt;tt&gt;2&lt;/tt&gt;, &lt;tt&gt;1&lt;/tt&gt;, and &lt;tt&gt;4&lt;/tt&gt; are actually instances of &lt;tt&gt;SmallInteger&lt;/tt&gt; objects. The &lt;tt&gt;+&lt;/tt&gt; message is sent to &lt;tt&gt;2&lt;/tt&gt; with an argument of &lt;tt&gt;1&lt;/tt&gt;, which responds by adding the value of the argument to its own value resulting in a value of 3. Then, the &lt;tt&gt;/&lt;/tt&gt; message with the argument &lt;tt&gt;4&lt;/tt&gt; is sent. The object responds by dividing its value by 4 which results in a final value of .75 for the expression.&lt;br /&gt;&lt;br /&gt;Some things can easily be conceptualized as objects, such as windows, streams, and data structures, while it can be difficult to think of others as objects, such as text, integers, colors, and truth values. Over-personification and the &lt;a href="http://zaemis.blogspot.com/2009/06/whats-wrong-with-oop.html"&gt;perspective of the grammatical predicate/direct object performing actions&lt;/a&gt; is backwards of how we speak and how we think.&lt;br /&gt;&lt;br /&gt;As awkward as the "everything is a" mindset it, I have to respect Kay for it. He intentionally adopted it so he and his team would be forced to think outside the box. &lt;a href="http://www.smalltalk.org/smalltalk/TheEarlyHistoryOfSmalltalk_Abstract.html"&gt;Kay admits&lt;/a&gt; "we were actually trying for a qualitative shift in belief structures-- a new Kuhnian paradigm in the same spirit as the invention of the printing press-- and thus took highly extreme positions which almost forced these new styles to be invented." I can respect his effort and appreciate the elegant design it resulted in, but I can't expect an 8-year old to understand passing code blocks as arguments and why the order of operations is different on the computer than in the classroom.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-7146063544492430921?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/7146063544492430921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-3-awkward.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7146063544492430921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7146063544492430921'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-3-awkward.html' title='Smalltalk Challenge: Post 3 - Awkward'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-7814241552798829278</id><published>2011-06-26T01:46:00.007-04:00</published><updated>2011-07-10T02:06:00.634-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 2 - Switching to Squeak</title><content type='html'>A quick survey of Smalltalk's keywords, constructs, and syntax isn't enough to understand how the language approaches programming. There is only a handful of keywords, no control structures, and the syntax is quirky in spots but is hardly exotic. To really get an appreciation, it's helpful to place the language in its historical context. Smalltalk wasn't intended to be a general purpose systems programming language like C, rather it was designed to &lt;a href="http://www.cosc.canterbury.ac.nz/wolfgang.kreutzer/cosc205/smalltalk1.html#history"&gt;allow ordinary people to take full advantage of their computers&lt;/a&gt; and to be easy enough for children to learn. The intended environment was immersive, interactive, and most-importantly visual. Smalltalk was more than a programming language, it was an entire operating environment.&lt;br /&gt;&lt;br /&gt;Xerox was working on the Dynabook at its Palo Alto Research Center in the early 1970's. The Dynabook was to have many features we now see in personal laptops and tablet devices (such as touch screens, mice, windowed display managers, etc.). &lt;a href="http://en.wikipedia.org/wiki/Alan_Kay"&gt;Alan Kay&lt;/a&gt; argued that existing languages were ill-suited and a new programming language was necessary for the end-user to realize the full potential of the system. He drew inspiration from the work of &lt;a href="http://en.wikipedia.org/wiki/Jean_Piaget"&gt;Jean Piaget&lt;/a&gt; and others in developmental psychology and constructionist learning, which set the direction of Smalltalk. The Dynabook project never came to fruition, but Smalltalk lives on, and both had a lasting influence on computing that we still see today.&lt;br /&gt;&lt;br /&gt;Given this background, I suspected something like Squeak would really be better suited for learning Smalltalk as it was intended since Squeak is the modern implementation of the language &lt;i&gt;and&lt;/i&gt; environment that was developed at Palo Alto. I asked Josh if it was okay to switch from GNU Smalltalk to Squeak. He agreed-- admitting that he only proposed GNU Smalltalk because it's what he already had on his system from Portage. I checked apt and was amazed to find Squeak in Ubuntu's repositories (with bets on the MotU pulling it without telling anyone within the next two releases). After running &lt;tt&gt;sudo apt-get install squeak-vm&lt;/tt&gt; and starting Squeak, I was staring at a pretty gaudy looking graphical environment.&lt;br /&gt;&lt;br /&gt;I took the liberty of running a "Hello World" program. The System Browser window is at the top, a Workspace window is in the middle, the Transcript window is at the bottom, and the Objects Library window is to the right. I entered the statement &lt;tt&gt;Transcript show: 'Hello World!'&lt;/tt&gt; in the Workspace, highlighted it, and chose "do it" from the popup menu.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://lh6.googleusercontent.com/-d7hh2lgcSGc/TgbImlp5EdI/AAAAAAAAARM/GLgOX_NEOV8/s800/squeak-1.png" width="425"/&gt;&lt;br /&gt;&lt;br /&gt;Every element is an object which you interact with by sending it messages. In the above example for instance, I interacted with the Transcript window by sending it the &lt;tt&gt;show:&lt;/tt&gt; message and the argument &lt;tt&gt;&lt;nobr&gt;'Hello World!'&lt;/nobr&gt;&lt;/tt&gt;. The window responded by displaying the text.&lt;br /&gt;&lt;br /&gt;I did a screen recording of another example to help give you a better idea what interaction in the graphical environment can look like. I placed a Star object on the world (the main "desktop" area) and used its Inspection window to send the messages &lt;tt&gt;borderWidth:&lt;/tt&gt; and &lt;tt&gt;rotationDegrees:&lt;/tt&gt;. The object responded by redrawing itself with a thicker border and different rotation.&lt;br /&gt;&lt;br /&gt;&lt;iframe width="425" height="349" src="http://www.youtube.com/embed/atvpEol7tSc" frameborder="0" allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Have you been challenged to learn a new language, or have you been learning/working with Smalltalk? Feel free to leave your comments about it below.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-7814241552798829278?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/7814241552798829278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7814241552798829278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7814241552798829278'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-2.html' title='Smalltalk Challenge: Post 2 - Switching to Squeak'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh6.googleusercontent.com/-d7hh2lgcSGc/TgbImlp5EdI/AAAAAAAAARM/GLgOX_NEOV8/s72-c/squeak-1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-3234560197734506797</id><published>2011-06-25T23:44:00.005-04:00</published><updated>2011-07-10T02:06:00.635-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Smalltalk'/><title type='text'>Smalltalk Challenge: Post 1 - Installing GNU Smalltalk</title><content type='html'>That's right... I'm the one who &lt;a href="http://www.blog.ghost-network.net/2011/06/the-challenge-learning-ocaml-first-2-hours/"&gt;challenged my coworker Josh&lt;/a&gt; to open his mind beyond Java by spending time with a new language and blogging about it. l At first I challenged him to learn &lt;a href="http://www.mozart-oz.org/"&gt;Oz&lt;/a&gt;, a language that combines the imperative, object-oriented, functional, logic, constraint, distributed, and concurrent programming paradigms (whew!). Unfortunately, apparently the 64-bit version of Mozart on Gentoo is broken at the moment and he didn't want to, as he put it, "build random shit on his box." So I proposed &lt;a href="http://caml.inria.fr/ocaml/index.en.html"&gt;OCaml&lt;/a&gt; as an alternative. While it may not combine seven programming paradigms, I'm positive functional programming will be enough to show him there's more to life than what Java offers.&lt;br /&gt;&lt;br /&gt;In return, for him to accept my challenge I had to agree to spend some time learning a language of his choosing too, and he set the number of required blog posts to 10. That's not too bad in my opinion since I enjoy looking at different programming languages anyway, but 10 posts seems a bit excessive (I would have been happy with 3). His first suggestion was &lt;a href="http://shakespearelang.sourceforge.net/"&gt;Shakespeare&lt;/a&gt;. Really? I made him pick a more serious language, which turned out to be GNU Smalltalk. Yes, let the record show I rejected his first proposal, but he also rejected mine... and also let the record show that I'm not afraid to use a compiler.&lt;br /&gt;&lt;br /&gt;My first attempt to install Smalltalk was through apt-get since I'm using an Ubuntu system right now, and of course I met up with the usual Ubuntu package bullshit...&lt;br /&gt;&lt;pre&gt;sudo apt-get install smalltalk&lt;br /&gt;E: Unable to locate package smalltalk&lt;br /&gt;&lt;br /&gt;sudo apt-get install gnu-smalltalk&lt;br /&gt;Package gnu-smalltalk is not available, but is referred to by&lt;br /&gt;another package. This may mean that the package is missing,&lt;br /&gt;has been obsoleted, or is only available from another source&lt;br /&gt;&lt;br /&gt;E: Package 'gnu-smalltalk' has no installation candidate&lt;/pre&gt;It was the &lt;a href="http://zaemis.blogspot.com/2010/12/ubuntu-packaging-please-get-your-act.html"&gt;SpiderMonkey fiasco&lt;/a&gt; all over again. Apparently GNU Smalltalk was &lt;a href="http://forum.world.st/GNU-Smalltalk-on-Ubuntu-missing-td2173959.html"&gt;removed from Ubuntu&lt;/a&gt; back in Lucid Lynx. I had to go to &lt;a href="http://smalltalk.gnu.org/"&gt;smalltalk.gnu.org&lt;/a&gt; instead and download the source. In just a few minutes I had a working binary using the usual &lt;tt&gt;configure&lt;/tt&gt;, &lt;tt&gt;make&lt;/tt&gt;, &lt;tt&gt;make install&lt;/tt&gt; mantra.&lt;br /&gt;&lt;br /&gt;There was one minor snag during compilation, though. Initially libtool reported that it couldn't find the name of the link library for &lt;tt&gt;libc.la&lt;/tt&gt;. A quick &lt;a href="http://lists.gnu.org/archive/html/help-smalltalk/2011-04/msg00160.html"&gt;Google search&lt;/a&gt; showed all I had to do was remove &lt;tt&gt;libc.la&lt;/tt&gt; and run make again.&lt;br /&gt;&lt;br /&gt;Now it's time to learn some Smalltalk!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update (6/29/11):&lt;/b&gt; I was able to compile GNU Smalltalk without experiencing the &lt;tt&gt;libc.la&lt;/tt&gt; issue by running &lt;tt&gt;&lt;nobr&gt;autoreconf -vi&lt;/nobr&gt;&lt;/tt&gt; before &lt;tt&gt;configure&lt;/tt&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-3234560197734506797?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/3234560197734506797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3234560197734506797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3234560197734506797'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/06/smalltalk-challenge-post-1.html' title='Smalltalk Challenge: Post 1 - Installing GNU Smalltalk'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-7551364189279714189</id><published>2011-06-04T18:21:00.001-04:00</published><updated>2011-06-04T18:23:41.663-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Unicode'/><title type='text'>Reading Unicode (UTF-8) in C</title><content type='html'>In working on scanner code for &lt;a href="https://github.com/tboronczyk/Kiwi"&gt;Kiwi&lt;/a&gt; I did a bit of reading up on &lt;a href="http://unicode.org/"&gt;Unicode&lt;/a&gt;. It's not really as difficult as one might think parsing UTF-8 character by character in C. In the end I opted to use &lt;a href="http://site.icu-project.org/"&gt;ICU&lt;/a&gt; so I could take advantage of its character class functions instead of rolling my own, but the by-hand method I thought was still worth sharing.&lt;br /&gt;&lt;br /&gt;Functions like &lt;tt&gt;getc()&lt;/tt&gt; read in a byte from an input stream. ASCII was the predominant encoding scheme and encoded characters in 7-8 bits, so reading a byte was effectively the same as reading a character. But you can only represent 255 characters using 8 bits, far too little to represent all the characters of the world's languages. The most common Unicode scheme is &lt;a href="http://en.wikipedia.org/wiki/UTF-8"&gt;UTF-8&lt;/a&gt;, is a multi-byte encoding scheme capable of representing  over 2 million characters using 4 bytes or less.&lt;br /&gt;&lt;br /&gt;The 128 characters of 7-bit ASCII encoding scheme are encoded the same, the most-significant bit is always 0. Other characters can be encoded as multiple bytes but the most-significant bit in such cases is always 1. The bit pattern in the first byte of such multi-byte characters too that make it easy to determine exactly how many bytes are used for the character.&lt;br /&gt;&lt;br /&gt;&lt;div style="clear: both; text-align: center;"&gt;&lt;img src="https://lh4.googleusercontent.com/-21zT4wUQhhg/TeqswvanP0I/AAAAAAAAAQA/FZgH4uSO7xw/s512/utf8bytes.png" style="width:95%"/&gt;&lt;/div&gt;&lt;br /&gt;The first bit serves as a flag. If set, the character is encoded using multiple bytes, and if not, the character is encoded using just one. Subsequent bits indicate the number of bytes used. Each byte in a multi-byte encoded character will aways start with the pattern "10".&lt;br /&gt;&lt;br /&gt;With that knowledge, one can write a wrapper that reads characters in from a UTF-8 encoded source one at a time. &lt;tt&gt;getc()&lt;/tt&gt; reads a byte at a time, and a quick peek at the significant bits determines if additional bytes must be read to fetch the entire character.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;string.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define U_MAX_BYTES 4&lt;br /&gt;&lt;br /&gt;unsigned short u_getc(FILE *stream, char *bytes) {&lt;br /&gt;    /* mask values for bit pattern of first byte in multi-byte&lt;br /&gt;     UTF-8 sequences: &lt;br /&gt;       192 - 110xxxxx - for U+0080 to U+07FF &lt;br /&gt;       224 - 1110xxxx - for U+0800 to U+FFFF &lt;br /&gt;       240 - 11110xxx - for U+010000 to U+1FFFFF */&lt;br /&gt;    static unsigned short mask[] = {192, 224, 240}; &lt;br /&gt;&lt;br /&gt;    unsigned short i, j; &lt;br /&gt;&lt;br /&gt;    /* initialize buffer */&lt;br /&gt;    memset(bytes, 0, U_MAX_BYTES); &lt;br /&gt;&lt;br /&gt;    /* read first byte into buffer */&lt;br /&gt;    bytes[0] = getc(stream);&lt;br /&gt;    if (bytes[0] == EOF) { &lt;br /&gt;        return 0; &lt;br /&gt;    } &lt;br /&gt;&lt;br /&gt;    /* check how many more bytes need to be read for&lt;br /&gt;     character */&lt;br /&gt;    i = 0;&lt;br /&gt;    if ((bytes[0] &amp;amp; mask[0]) == mask[0]) i++;&lt;br /&gt;    if ((bytes[0] &amp;amp; mask[1]) == mask[1]) i++;&lt;br /&gt;    if ((bytes[0] &amp;amp; mask[2]) == mask[2]) i++;&lt;br /&gt;&lt;br /&gt;    /* read subsequent character bytes */&lt;br /&gt;    j = 0;&lt;br /&gt;    while (j &lt; i) {&lt;br /&gt;        j++;&lt;br /&gt;        bytes[j] = getc(stream);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* return number of bytes read into buffer */&lt;br /&gt;    return i + 1;&lt;br /&gt;}&lt;/pre&gt;The wrapper function &lt;tt&gt;u_getc()&lt;/tt&gt; is passed an open file handle and a buffer to store the character. It returns the number of bytes read into the buffer.&lt;pre&gt;int main(int argc, char **argv) {&lt;br /&gt;    /* allocating +1 for null gives ability to print character&lt;br /&gt;     as string */&lt;br /&gt;    char *bytes = (char*)calloc(U_MAX_BYTES + 1, sizeof(char)); &lt;br /&gt;&lt;br /&gt;    /* read and print until end of file */&lt;br /&gt;    while (u_getc(stdin, bytes)) { &lt;br /&gt;        printf("%s\n", bytes); &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return 0; &lt;br /&gt;}&lt;/pre&gt;Grouping characters into tokens such as operators and numeric literals is easy because UTF-8 is backward compatible with 7-bit ASCII, which allows performing character tests like &lt;tt&gt;byte[0] == '+'&lt;/tt&gt; and &lt;tt&gt;isdigit(byte[0])&lt;/tt&gt;. But it was the need to test multi-byte sequences that ultimately lead me to use ICU.  Writing and testing a function that properly identifies membership in the set of &lt;a href="http://unicode.org/reports/tr31/"&gt;14,725+ possible characters&lt;/a&gt; that could appear in an identifier name wasn't a tempting prospect.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-7551364189279714189?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/7551364189279714189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/06/reading-unicode-utf-8-by-hand-in-c.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7551364189279714189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7551364189279714189'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/06/reading-unicode-utf-8-by-hand-in-c.html' title='Reading Unicode (UTF-8) in C'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh4.googleusercontent.com/-21zT4wUQhhg/TeqswvanP0I/AAAAAAAAAQA/FZgH4uSO7xw/s72-c/utf8bytes.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6884124141894039935</id><published>2011-05-30T23:19:00.003-04:00</published><updated>2011-05-31T09:38:32.252-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Language Design'/><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><title type='text'>OO in Language Design</title><content type='html'>If you were to create a new programming language, and you wanted to support object oriented programming with it, what would it look like? An object is a set of instance data and various functions that work with it.  In Java, they're specified by first grouping the variables and functions together in a class, and then creating an instance from the class definition. In JavaScript, functions are dynamically attached to the instance data (or it's prototype). This is an intentional over-simplification but does highlight the fact that different programming languages approach working with objects differently. I've been thinking about objects and working with structured code in relation to &lt;a href="https://github.com/tboronczyk/Kiwi"&gt;Kiwi&lt;/a&gt; and it depresses me how much the object oriented school of thought that started with C++ and came to fruition in Java has influenced our industry.&lt;br /&gt;&lt;br /&gt;Of course there are the so-called &lt;a href="http://en.wikipedia.org/wiki/Object-oriented_design#Object-oriented_concepts"&gt;five concepts of object oriented design&lt;/a&gt;, which says a design that meets the following criteria is considered object-oriented (OO):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Object/Class&lt;/li&gt;&lt;li&gt;Information Hiding&lt;/li&gt;&lt;li&gt;Inheritance&lt;/li&gt;&lt;li&gt;Interface&lt;/li&gt;&lt;li&gt;Polymorphism&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;But I'm not so sure I'm convinced. A coworker accused me of trying to re-define it:  &lt;br /&gt;&lt;br /&gt;&lt;div style="padding-left:1em;"&gt;&lt;b&gt;Coworker:&lt;/b&gt; So now we're redefining what OO is too... care to define common words as well?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Me:&lt;/b&gt; I'm not redefining it per se... just calling bullshit where I see bullshit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Coworker:&lt;/b&gt; Excuse while I go outside and laugh loudly.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Me:&lt;/b&gt; Sorry my name isn't &lt;a href="http://martinfowler.com/"&gt; Martin Fowler&lt;/a&gt; so my opinion probably doesn't matter much, but I still smell bullshit.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;If we think about programming in C for a moment, a language that isn't considered to support OO practices, we can still encapsulate our code and provide an interface for data manipulation. Member variables are placed in a &lt;tt&gt;struct&lt;/tt&gt;, public methods are functions listed in a header file, and private methods exist only in the code file. Encapsulating in this case depends on an understanding of variable and file scoping rules of the language, not the existence of some &lt;tt&gt;class&lt;/tt&gt;, &lt;tt&gt;public&lt;/tt&gt;, &lt;tt&gt;protected&lt;/tt&gt;, and &lt;tt&gt;private&lt;/tt&gt; keywords.&lt;br /&gt;&lt;br /&gt;We have to pass a pointer to the instance &lt;tt&gt;class&lt;/tt&gt; into the functions, but that still happens in languages that are considered to be OO languages too; it's just syntactic sugar that automatically passes it and assigns it to &lt;tt&gt;this&lt;/tt&gt;. It's difficult to ignore the similarity between &lt;tt&gt;foo.doSomething()&lt;/tt&gt; and &lt;tt&gt;doSomething(foo)&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Java has developers define the method functions in the same code unit as the member variables. Others allow defining them separately, and then associate them in some way later. C++ does this through file and namespacing, and &lt;a href="http://zaemis.blogspot.com/2010/12/week-with-golang-day-4.html"&gt;Go does this with interfaces&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If we were to think of instances of objects in terms as payload structs, then is inheritance really necessary? We don't extend a class for example because we have a protected integer member we want to reuse, we do it for the functionality provided by method functions. Inheritance supposedly helps with code-organization and promotes re-use, but I'd argue not essential for OO. In fact, the proliferation of OO far exceeds the amount of code we actually end up reusing.&lt;br /&gt;&lt;br /&gt;Polymorphism probably isn't really needed either for OO. Data typing is all about the underlying semantic meaning of data and what operations are allowed to be performed on it. What it means to "add" two strings together and what it means to "add" two integers together are different even though both are aggregate operations. Typing is less relevant in dynamic languages like PHP and Ruby. We don't care what type an object is so long as we can call a method on it. The concept of polymorphism is only important in statically-typed languages, and promoting it as a core OO concept means a true dynamically typed language could never be object oriented.&lt;br /&gt;&lt;br /&gt;The way I see it, encapsulation begets abstraction. Inheritance is about reusability, not objects. Interface is a design pattern that attempts to overcome difficulty for reusing code from different objects. &lt;i&gt;Pure&lt;/i&gt; object oriented programming seems really to be about encapsulation and message passing, while the concepts above seem more concerned about structure.&lt;br /&gt;&lt;br /&gt;It can be argued that the software industry is in the mess it's in right now because of the over-definition and application of intolerant ideas about OO, and a refusal to acknowledge other schools of thought on the subject. But if I'm taking on the responsibility to create a new language, then I'm going to take the time to think about such things and not just follow the herd. I want to create something better, not just a better Java.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6884124141894039935?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6884124141894039935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/05/oo-in-language-design.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6884124141894039935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6884124141894039935'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/05/oo-in-language-design.html' title='OO in Language Design'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-3452916728056093134</id><published>2011-05-15T14:21:00.000-04:00</published><updated>2011-05-15T14:21:16.455-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><title type='text'>Spaghetti Code Considered Harmful</title><content type='html'>To chefs and epicureans, spaghetti is a good thing-- it's inexpensive, easy to make, and very versatile. But spaghetti isn't so appetizing to a programmer. The phrase "spaghetti code" is an all-too-common pejorative we programmers use to describe horrible code, whether it's difficult to understand, poorly organized, or just plain long-winded. And there-in lays the problem. What really constitutes spaghetti code is subjective; I've yet to hear a concrete definition or standard metric that measures it.&lt;br /&gt;&lt;br /&gt;I've seen PHP code that amounts to nothing more than a giant &lt;tt&gt;switch&lt;/tt&gt; construct... a hundred lines here to handle this condition over here, another hundred or so lines in the branch for that condition over there, maybe a dozen conditions... you get the idea. But such code isn't necessarily spaghetti. What's wrong with it is not that it's unreadable, I would argue, but rather there is a lack of encapsulation. There's a greater chance of inadvertently modifying the wrong variable 800 lines down in some unknown branch, but scoping isn't spaghetti. The code may otherwise be beautifully formatted with the coding standard &lt;i&gt;du jour&lt;/i&gt;, and the logic might be crystal clear.&lt;br /&gt;&lt;br /&gt;I've also seen OOP code that has been so meticulously refactored that it would bring a tear of joy to just about any DRY-advocate's eye, but that doesn't always mean the code is well organized or easy to follow. It can be frustrating to trace through deep inheritance chains without the help of a modern IDE with project support. IDEs are tools that should help make working with code easier, not be a requirement to navigate what is essentially a set of text files. New professionals coming out of college now with an OOP perspective would be comfortable with such code. They view the same procedural code an old-time C programmer would be comfortable with as messy, unorganized, sloppy spaghetti.&lt;br /&gt;&lt;br /&gt;An informal poll I took asked a handful of developers to try to explain what is spaghetti code. They all agreed that it was a term used to describe bad code, but everyone has his or her own opinion as to what aspects would make them label it spaghetti:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Spaghetti code is code that is written quickly and doesn't follow the accepted standard. &lt;/li&gt;&lt;li&gt;Spaghetti code is any code that uses &lt;tt&gt;goto&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;Spaghetti code is code written by a beginner who's learning to program in Basic. &lt;/li&gt;&lt;li&gt;Spaghetti code is like spaghetti in that after you've digested it you are fatigued.&lt;/li&gt;&lt;/ul&gt;It's trivial to find code samples that relegate such metrics as mere preference, because each one relies on a subjective perception of quality.&lt;br /&gt;&lt;br /&gt;The best response I received was from a friend and former co-worker, Sean H. "Spaghetti code is what we call other people's code when we think it's a pile of blackened shit that's baked in the sun and has flies swarming about it but we still want to be polite." Spaghetti code really has nothing to do with code, but rather how we choose to interact with one another. Lacking a proper definition but carrying a negative connotation, spaghetti is just complaining about other people's work which is not beneficial to ourselves or to the quality of the code we produce/maintain.&lt;br /&gt;&lt;br /&gt;Some programmers are very protective of the code they write and they can react in a variety of ways to people who call their work spaghetti. Depending on their personality, in an extreme case they may view such comments as a personal attack and become overtly confrontational. Few people like to be challenged on their way of doing something. In a more subtle case, the programmer may begin to resent others. He feels misunderstood and begins to draw inward, subconsciously severing communication channels.&lt;br /&gt;&lt;br /&gt;But besides negatively affecting others, our complaining about spaghetti code hurts ourselves too. It's easier to motivate ourselves when tasked with fixing a bug when we're not dreading having to trudge through spaghetti. When we label code as spaghetti code, we are actually creating roadblocks that hamper ourselves and artificially increase the difficulty of the task at hand. A better perspective to have is that we have been given the opportunity to use our skills to fix something and to make it better. Constant complaining only reinforces the wrong attitude and makes it easier to become disillusion with our craft; negativity "sucks the life out of you" and doesn't serve to create a better work environment.&lt;br /&gt;&lt;br /&gt;It's almost always easier to complain and set oneself up for failure rather than success. Should I stop harping on Java? Probably. Should I not let my skin crawl every time I run into Zend Framework? Maybe. Though I consider myself successful, how much more successful could I be if I didn't put up mental blocks for myself over what amounts to other people's preference? I have no idea. Old habits die hard, but it's a worthy goal to strive for to stop alienating others and making life difficult for myself by complaining about spaghetti code. Feel free to join me in doing so.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-3452916728056093134?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/3452916728056093134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/05/spaghetti-code-considered-harmful.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3452916728056093134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3452916728056093134'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/05/spaghetti-code-considered-harmful.html' title='Spaghetti Code Considered Harmful'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-570110856902560716</id><published>2011-04-12T17:15:00.001-04:00</published><updated>2011-04-12T17:16:09.999-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>Bearing Your Cross</title><content type='html'>There's the old saying, "we all have our own crosses to bear." As cliché as old clichés are, they're generally true. Life is full of injustice and hardship. For some it may be an addiction to drugs or alcohol. For others, it may be caring for an elderly relative. The important thing isn't what your cross is, rather how you bear it.&lt;br /&gt;&lt;br /&gt;I myself struggle with depression. I've learned to live with it with the help of medication and coping strategies. There are still bad days here and there, but I do my best to avoid complaining about it. I have gone further in life by believing in myself than I have by pitying myself. Depression is my cross to bear, and I focused my energy to learning programming which I can now share with others.&lt;br /&gt;&lt;br /&gt;I met an impressive girl the other day who shared with me her struggle to overcome anorexia. She drew the strength from it to go on and start her own business selling custom fetish gear. She wants people to know they can still feel comfortable as whoever they are regardless of how they look, if they're fat, thin, bald, etc.&lt;br /&gt;&lt;br /&gt;My best friend's grandmother ended up unexpectedly raising 5 children and several foster children on her own after she was widowed.&lt;br /&gt;&lt;br /&gt;I know rich people and poor people, healthy people and sick people, happy people and miserable people. Life dealt each one an unfair hand in one way or another, but each has something different to offer. The next time you feel the urge to complain about life's difficulties, stop for a moment and ask yourself if that's the right thing to do. More often than not you can tap into your struggles as a source of experience and strength to help others. And when you do, your cross won't seem so heavy anymore.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-570110856902560716?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/570110856902560716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/04/bearing-your-cross.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/570110856902560716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/570110856902560716'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/04/bearing-your-cross.html' title='Bearing Your Cross'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-7585965467049853791</id><published>2011-03-20T23:52:00.003-04:00</published><updated>2011-03-21T00:17:36.075-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><title type='text'>Resuming scp</title><content type='html'>I was transferring a file from one system to another at work with scp when the connection dropped. It was a substantially sized file and I didn't want to start the transfer over again, but unfortunately scp doesn't support resume. That's when I remembered rsync. With rsync I was able to continue the transfer where it left off, and afterward I had the idea to set the following alias in my &lt;tt&gt;.bashrc&lt;/tt&gt; file.&lt;br /&gt;&lt;pre&gt;alias scp='rsync -vPe ssh'&lt;/pre&gt;Now when I transfer files with scp, I'm really using rsync and I don't have to worry about flaky network drops.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-7585965467049853791?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/7585965467049853791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/03/scp-resume.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7585965467049853791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7585965467049853791'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/03/scp-resume.html' title='Resuming scp'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2857168610357994553</id><published>2011-03-15T23:01:00.004-04:00</published><updated>2011-06-05T00:39:24.216-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>Creepy JavaScript Tracking</title><content type='html'>I recently began allergy shots so my new Monday morning routine includes me sitting in a doctor's office for 30 minutes (I must wait after receiving the shots and be checked by a nurse to make sure there was no reaction). With nothing else better to do while I waited last week, I started playing around with some JavaScript. This is what I came up with:&lt;br /&gt;&lt;pre&gt;&amp;lt;html&amp;gt;&lt;br /&gt; &amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;title&amp;gt;Test&amp;lt;/title&amp;gt;&lt;br /&gt;  &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;window.onload = function () {&lt;br /&gt;    var mX = 0,&amp;nbsp; mY = 0,&lt;br /&gt;        sX = 0,&amp;nbsp; sY = 0,&lt;br /&gt;        queue = [],&lt;br /&gt;        interval = 200,&lt;br /&gt;        recIntv = null,&lt;br /&gt;        playIntv = null,&lt;br /&gt;        b = document.body,&lt;br /&gt;        de = document.documentElement,&lt;br /&gt;        cursor = document.getElementById("cursor"),&lt;br /&gt;        record = document.getElementById("record"),&lt;br /&gt;        play = document.getElementById("play");&lt;br /&gt;&lt;br /&gt;    window.onmousemove = function (e) {&lt;br /&gt;        e = e || window.event;&lt;br /&gt;        if (e.pageX || e.pageY) {&lt;br /&gt;            mX = e.pageX;&lt;br /&gt;            mY = e.pageY;&lt;br /&gt;        } else {&lt;br /&gt;            mX = e.clientX + (de.scrollLeft || b.scrollLeft) - &lt;br /&gt;                (de.clientLeft || 0);&lt;br /&gt;            mY = e.clientY + (de.scrollTop || b.scrollTop) -&lt;br /&gt;                (de.clientTop || 0);&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    window.onscroll = function () {&lt;br /&gt;        if (window.pageXOffset || window.pageYOffset) {&lt;br /&gt;            sX = window.pageXOffset;&lt;br /&gt;            sY = window.pageYOffset;&lt;br /&gt;        } else {&lt;br /&gt;            sX = de.scrollLeft || b.scrollLeft;&lt;br /&gt;            sY = de.scrollTop || b.scrollTop;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    record.onclick = function () {&lt;br /&gt;        if (recIntv === null) {&lt;br /&gt;            queue.length = 0;&lt;br /&gt;            recIntv = setInterval(function () {&lt;br /&gt;                queue.push([mX, mY, sX, sY]);&lt;br /&gt;            }, interval);&lt;br /&gt;            this.innerHTML = "Stop";&lt;br /&gt;            cursor.style.display = "none";&lt;br /&gt;            play.disabled = true;&lt;br /&gt;        } else {&lt;br /&gt;            this.innerHTML = "Record";&lt;br /&gt;            clearInterval(recIntv);&lt;br /&gt;            recIntv = null;&lt;br /&gt;            play.disabled = false;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    play.onclick = function () {&lt;br /&gt;        var i = 0;&lt;br /&gt;        if (playIntv === null) {&lt;br /&gt;            cursor.style.display = "inherit";&lt;br /&gt;            play.disabled = record.disabled = true;&lt;br /&gt;            playIntv = setInterval(function () {&lt;br /&gt;                if (i &amp;lt; queue.length) {&lt;br /&gt;                    cursor.style.left = queue[i][0] + "px";&lt;br /&gt;                    cursor.style.top = queue[i][1] + "px";&lt;br /&gt;                    window.scrollTo(queue[i][2], queue[i][3]);&lt;br /&gt;                    i++;&lt;br /&gt;                } else {&lt;br /&gt;                    clearInterval(playIntv);&lt;br /&gt;                    playIntv = null;&lt;br /&gt;                    play.disabled = record.disabled = false;&lt;br /&gt;                }&lt;br /&gt;            }, interval);&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;};&lt;br /&gt;  &amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;/head&amp;gt;&lt;br /&gt; &amp;lt;body&amp;gt;&lt;br /&gt;  &amp;lt;p&amp;gt;Press Record to track mouse movements and scrolling.&lt;br /&gt;Press Play to view.&amp;lt;/p&amp;gt;&lt;br /&gt;  &amp;lt;button id="record"&amp;gt;Record&amp;lt;/button&amp;gt;&lt;br /&gt;  &amp;lt;button id="play" disabled="disabled"&amp;gt;Play&amp;lt;/button&amp;gt;&lt;br /&gt;  &amp;lt;img id="cursor" src="cursor.png"&lt;br /&gt;   style="position:absolute; display:none;"/&amp;gt;&lt;br /&gt; &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;Essentially the code watches your mouse movements and can play them back for you. A callback function is attached to the &lt;tt&gt;window&lt;/tt&gt; object's &lt;tt&gt;onmousemove&lt;/tt&gt; event to obtain the coordinates of the cursor (&lt;tt&gt;mX&lt;/tt&gt; and &lt;tt&gt;mY&lt;/tt&gt;), and a callback is attached to the &lt;tt&gt;onscroll&lt;/tt&gt; event to obtain the scroll position of the window (&lt;tt&gt;sX&lt;/tt&gt; and &lt;tt&gt;sY&lt;/tt&gt;). To record the input, a simple function is called every 200 milliseconds to push the coordinate values onto a queue. Playback is done by reading from the queue and positioning a sprite and scrolling the window accordingly.&lt;br /&gt;&lt;br /&gt;So what's the practical value of this, you may ask? Probably not much beyond spying.&lt;br /&gt;&lt;br /&gt;Right from the early days of the commercial Internet, your online activity has been tracked and analyzed. Unfortunately (or fortunately, depending on your perspective) efforts over the years have increased the amount of data that can be collected and improved its accuracy. Gone are the days of relying solely on httpd access logs; today there is &lt;a href="http://www.google.com/analytics/"&gt;Google Analytics&lt;/a&gt;, &lt;a href="http://www.schneier.com/blog/archives/2010/09/evercookies.html"&gt;evercookies&lt;/a&gt;, and even HBGary's &lt;a href="http://arstechnica.com/tech-policy/news/2011/02/how-one-security-firm-tracked-anonymousand-paid-a-heavy-price.ars"&gt;Aaron Barr's social mapping scheme&lt;/a&gt;. We are being watched in more ways than we can imagine.&lt;br /&gt;&lt;br /&gt;I showed the code to several friends and the consensus was the same. If there was any practical value at all to it, most likely that would be tracking. It's a trivial exercise to adapt it so the coordinates are posted back to the server for storage in a database. Once there, all sorts of analysis could be performed on them. Perhaps a heat map could be constructed to see which products on an e-commerce catalog page shoppers thought about clicking on. Marketers could then fine-tune their images and layout to increase conversion.&lt;br /&gt;&lt;br /&gt;I don't have any intention of working on this code anymore; it's served its purpose for me as a brief diversion. The questions I've begun to ponder as a result of it though will endure longer than 20 minutes. Is this sort of tracking already in use, and if so then by whom? I'm not the first to play with this. What would be an easy way to thwart such tracking? Such tracking would probably happen unknowingly and it'd be unlikely there would be any opt-out. Where does one draw the ethical line between tracking and spying? It's understandable someone would want to get a better understanding of how their site is being used, but watching mouse movements seems kind of creepy.&lt;br /&gt;&lt;br /&gt;So what are your thoughts? Leave your comments below and let me know what you think.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE 6/5/2011:&lt;/b&gt; I've uploaded this code to my &lt;a href="https://github.com/tboronczyk/JavaScript-Experiments"&gt;JavaScript Experiments repository&lt;/a&gt; at GitHub if anyone is interested in playing around with it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2857168610357994553?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2857168610357994553/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/03/creepy-tracking.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2857168610357994553'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2857168610357994553'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/03/creepy-tracking.html' title='Creepy JavaScript Tracking'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-372455147241067863</id><published>2011-01-08T20:40:00.006-05:00</published><updated>2011-01-28T09:48:02.792-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Geolocation'/><title type='text'>Geolocation Search</title><content type='html'>Services that allow users to identify nearby points of interest continue to grow in popularity. I'm sure we're all familiar with social websites that let you search for the profiles of people near a postal code, or mobile applications that use geolocation to identify Thai restaurants within walking distance. It's surprisingly simple to implement such functionality, and in this post I will discuss how to do so.&lt;br /&gt;&lt;br /&gt;The first step is to obtain the latitude and longitude coordinates of any locations you want to make searchable. In the restaurant scenario, you'd want the latitude and longitude of each eatery. In the social website scenario, you'd want to obtain a list of postal codes with their centroid latitude and longitude.&lt;br /&gt;&lt;br /&gt;In general, postal code-based geolocation is a bad idea; their boundaries rarely form simple polygons, the area they cover vary in size, and are subject to change based on the whims of the postal service. But many times we find ourselves stuck on a client project that calls for things we know better than to do, so I'll spare you my rant and instead ask that you keep the following in mind:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;ZCTAs are not ZIP codes&lt;/b&gt; so do not use them as such. Some people recommend using the &lt;a href="http://www.census.gov/geo/ZCTA/zcta.html"&gt;US Census Bureau's 2000 ZCTA dataset&lt;/a&gt; as freely available ZIP code latitude/longitude information for the United States, but the Bureau's own website warns ZCTA codes are designed to label census blocks and do not always correspond to ZIP codes assigned to the same area by the US Postal Service. Unpopulated areas such as lakes and forests may have their own ZCTA code, while smaller ZIP codes may not even "appear in the ZCTA universe."&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Postal codes are volatile&lt;/b&gt; so make sure you understand your dataset provider's update policies. &lt;a href="http://www.zipinfo.com/"&gt;CD Light, LLC&lt;/a&gt; offers a line of commercial datasets which they license from the US Postal Service and Canada Post Corporation and then augment and maintain using a variety of additional sources. New codes are added and obsolete codes are removed from their datasets. Quarterly and monthly updates are made available through reasonably priced subscription plans. &lt;a href="http://federalgovernmentzipcodes.us/"&gt;federalgovernmentzipcodes.us&lt;/a&gt; on the other hand offers a free US ZIP code dataset that is irregularly-maintained using a smaller set of additional sources. Obsolete ZIP codes are included but marked "decommissioned." It's not clear however which company or individual is behind the offering.&lt;/li&gt;&lt;/ul&gt;Regardless if you're hosting your dataset yourself or using a web service such as &lt;a href="http://geocoder.ca/"&gt;GeoCoder.ca&lt;/a&gt;, it's still not a bad idea to familiarize yourself with what efforts are taken to build it from current information and to maintain its accuracy. It's better to have more-specific/accurate data than not.&lt;br /&gt;&lt;br /&gt;The second step is to develop an appropriate strategy to search your data. You don't want to calculate the distance to all target locations' coordinates from a given origin; this naive, brute-force search is rarely desirable, even if the dataset is small and your application/site traffic is low. My approach is to calculate the latitude and longitude coordinates for a search perimeter's north, east, south, and west bounds (bearings of 0&amp;deg;, 90&amp;deg;, 180&amp;deg;, and -90&amp;deg; or 270&amp;deg; respectively). I can then search the subset of records that have locations which falls within this bounding-box.&lt;br /&gt;&lt;br /&gt;I use the following formulas to calculate target coordinates and restrict my dataset search:&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img border=0 src="http://lh5.ggpht.com/_seHKqAQg2nk/TSkTTfo2-kI/AAAAAAAAAOo/rq-uHqN2GS8/geo-formula-destination.png"/&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;where:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;d&lt;/i&gt; is distance&lt;/li&gt;&lt;li&gt;&lt;i&gt;R&lt;/i&gt; is the Earth's radius (&lt;a href="http://earth-info.nga.mil/GandG/wgs84/"&gt;WGS84 model&lt;/a&gt; semi-major axis is 3,963.19 miles)&lt;/li&gt;&lt;li&gt;&lt;i style="font-size:130%;"&gt;&amp;#x1D69;&lt;/i&gt; is latitude&lt;/li&gt;&lt;li&gt;&lt;i&gt;&amp;lambda;&lt;/i&gt; is longitude&lt;/li&gt;&lt;li&gt;&lt;i&gt;&amp;theta;&lt;/i&gt; is bearing&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Implemented in code, the formulas look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-size:75%;"&gt;// calculate destination lat/lon given a starting point, bearing, and distance&lt;br /&gt;function destination($lat,$lon, $bearing, $distance,$units="mi") {&lt;br /&gt;    $radius = strcasecmp($units, "km") ? 3963.19 : 6378.137;&lt;br /&gt;    $rLat = deg2rad($lat);&lt;br /&gt;    $rLon = deg2rad($lon);&lt;br /&gt;    $rBearing = deg2rad($bearing);&lt;br /&gt;    $rAngDist = $distance / $radius;&lt;br /&gt;&lt;br /&gt;    $rLatB = asin(sin($rLat) * cos($rAngDist) + &lt;br /&gt;        cos($rLat) * sin($rAngDist) * cos($rBearing));&lt;br /&gt;&lt;br /&gt;    $rLonB = $rLon + atan2(sin($rBearing) * sin($rAngDist) * cos($rLat), &lt;br /&gt;                           cos($rAngDist) - sin($rLat) * sin($rLatB));&lt;br /&gt;&lt;br /&gt;    return array("lat" =&amp;gt; rad2deg($rLatB), "lon" =&amp;gt; rad2deg($rLonB));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;which a simple wrapper function can then call repeatedly with different bearings to determine the search bounds:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-size:75%;"&gt;// calculate bounding box&lt;br /&gt;function bound($lat,$lon, $distance,$units="mi") {&lt;br /&gt;return array("N" =&amp;gt; destination($lat,$lon,   0, $distance,$units),&lt;br /&gt;             "E" =&amp;gt; destination($lat,$lon,  90, $distance,$units),&lt;br /&gt;             "S" =&amp;gt; destination($lat,$lon, 180, $distance,$units),&lt;br /&gt;             "W" =&amp;gt; destination($lat,$lon, 270, $distance,$units));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Records that are located within this search area still need to be filtered, and I use the following formula to calculate the distance between two coordinates:&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img border=0 src="http://lh4.ggpht.com/_seHKqAQg2nk/TSkTTVqp8KI/AAAAAAAAAOs/acgJSs9N1RI/geo-formula-haversine.png"/&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;Implemented in code, the formula look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-size:75%;"&gt;// calculate distance between two lat/lon coordinates&lt;br /&gt;function distance($latA,$lonA, $latB,$lonB, $units="mi") {&lt;br /&gt;    $radius = strcasecmp($units, "km") ? 3963.19 : 6378.137;&lt;br /&gt;    $rLatA = deg2rad($latA);&lt;br /&gt;    $rLatB = deg2rad($latB);&lt;br /&gt;    $rHalfDeltaLat = deg2rad(($latB - $latA) / 2);&lt;br /&gt;    $rHalfDeltaLon = deg2rad(($lonB - $lonA) / 2);&lt;br /&gt;&lt;br /&gt;    return 2 * $radius * asin(sqrt(pow(sin($rHalfDeltaLat), 2) +&lt;br /&gt;        cos($rLatA) * cos($rLatB) * pow(sin($rHalfDeltaLon), 2)));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;A search using these functions would look like this (assume &lt;tt&gt;$latitude&lt;/tt&gt; and &lt;tt&gt;$longitude&lt;/tt&gt; are given and provide the origin coordinates, and &lt;tt&gt;$distance&lt;/tt&gt; and &lt;tt&gt;$units&lt;/tt&gt; provide the desired search radius):&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-size:75%;"&gt;$b = bound($latitude,$longitude, $distance,$units);&lt;br /&gt;$query = "SELECT location_name, address, city, state, zip_code,&lt;br /&gt;    latitude, longitude FROM locations WHERE&lt;br /&gt;    latitude BETWEEN {$b["S"]["lat"]} AND {$b["N"]["lat"]} AND&lt;br /&gt;    longitude BETWEEN {$b["W"]["lon"]} AND {$b["E"]["lon"]}";&lt;br /&gt;    $result = $db-&amp;gt;query($query);&lt;br /&gt;&lt;br /&gt;    $locations = array();&lt;br /&gt;    while ($row = $result-&amp;gt;fetch(PDO::FETCH_ASSOC)) {&lt;br /&gt;    $dist = distance($latitude,$lonitude, $row["latitude"],$row["longitude"], $units);&lt;br /&gt;    if ($dist &amp;lt;= $distance) {&lt;br /&gt;         $locations[] = array("name"     =&amp;gt; $row["location_name"],&lt;br /&gt;                              "address"  =&amp;gt; $row["address"],&lt;br /&gt;                              "city"     =&amp;gt; $row["city"],&lt;br /&gt;                              "state"    =&amp;gt; $row["state"],&lt;br /&gt;                              "zip_code" =&amp;gt; $row["zip_code"],&lt;br /&gt;                              "distance" =&amp;gt; round($dist, 2));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;A deep understanding of the mathematics used in navigation is nice to have, but is not truly necessary. We're lucky to live in an age where &lt;a href="http://www.movable-type.co.uk/scripts/latlong.html"&gt;finding suitable formulas&lt;/a&gt; is just a quick Internet search away, and discussions on the trade-offs between their simplicity and accuracy are easy to find. The formulas I used are based on the Haversine Formula which have been accurate enough for my needs. Others such as &lt;a href="http://en.wikipedia.org/wiki/Vincenty's_formulae"&gt;Vincenty's Formulae&lt;/a&gt; take into account the ellipsoidal nature of the Earth to produce more accurate results, but I'm helping people locate near-by friends or businesses... not programming cruise missiles.&lt;br /&gt;&lt;br /&gt;The final step is obtaining origin coordinates. In the postal code example from the beginning you can look up the code's centroid latitude and longitude and use those as your search origin. If your target audience is receptive, you may want to consider taking advantage of the JavaScript &lt;a href="http://www.w3.org/TR/geolocation-API/"&gt;Geolocation API&lt;/a&gt; defined by the W3C. The API exposes the &lt;tt&gt;navigator.geolocation&lt;/tt&gt; object which can obtain the user's current location. A user will rarely know his or her exact coordinates, but many Internet-enabled devices and smartphones now ship with GPS capabilities which the browser can access. &lt;tt&gt;navigator.geolocation.getCurrentPosition()&lt;/tt&gt; causes the brower to request permission from the user to report his or her location, and if permission is granted will invoke a specified callback function.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-size:75%;"&gt;&amp;lt;form&amp;gt;&lt;br /&gt; Search &amp;lt;input id="txtDist" maxlength="3" name="distance" size="3" type="text"/&amp;gt;&lt;br /&gt; &amp;lt;select name="units"&amp;gt;&lt;br /&gt;  &amp;lt;option value="mi"&amp;gt;mi&amp;lt;/option&amp;gt;&lt;br /&gt;  &amp;lt;option value="km"&amp;gt;km&amp;lt;/option&amp;gt;&lt;br /&gt; &amp;lt;/select&amp;gt; from&amp;lt;br/&amp;gt;&lt;br /&gt; &amp;lt;input checked="checked" name="searchBy" type="radio" value="zip"/&amp;gt;ZIP code&lt;br /&gt; &amp;lt;input maxlength="5" name="zipCode" size="5" type="text"/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt; &amp;lt;input id="coords" name="searchBy" type="radio" value="coords"/&amp;gt;coordinates&lt;br /&gt; &amp;lt;input id="txtLat" maxlength="10" name="latitude" size="6" type="text"/&amp;gt; Lat.&lt;br /&gt; &amp;lt;input id="txtLon" maxlength="10" name="longitude" size="6" type="text"/&amp;gt; Lon.&amp;lt;br/&amp;gt;&lt;br /&gt; &amp;lt;input type="submit" value="Search"/&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;(function () {&lt;br /&gt;    function setCoords(pos) {&lt;br /&gt;        document.getElementById("coords").checked = true;&lt;br /&gt;        document.getElementById("txtLat").value = pos.coordinates.latitude;&lt;br /&gt;        document.getElementById("txtLon").value = pos.coordinates.longitude;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (navigator.geolocation) {&lt;br /&gt;        navigator.geolocation.getCurrentPosition(setCoords);&lt;br /&gt;    }&lt;br /&gt;})();&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;br /&gt;Hopefully you now seen how relatively easy it is to support searching nearby points of interest in your web-application. First and foremost it is important to maintain a good dataset of target coordinates, since though users will understand the search results to be approximations, you can never return good results with bad data. Implementing algorithms necessary to search the set efficiently is relatively straightforward and I have shown you the approach I use; other algorithms and formulas can be found and implemented if you need more accurate results. And modern APIs like navigator.geolocation make it possible for you to offer new ways to your users to interact with your data. Feel free to share your thoughts and experiences in the comments section below.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Special thanks&lt;/b&gt; to &lt;a href="http://matthewturland.com/"&gt;Matthew Turland&lt;/a&gt; and &lt;a href="http://daveyshafik.com/"&gt;Davey Shafik&lt;/a&gt; who both helped me out immensely when I first got my feet wet with geolocation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-372455147241067863?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/372455147241067863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2011/01/geolocation-search.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/372455147241067863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/372455147241067863'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2011/01/geolocation-search.html' title='Geolocation Search'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_seHKqAQg2nk/TSkTTfo2-kI/AAAAAAAAAOo/rq-uHqN2GS8/s72-c/geo-formula-destination.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5330679870314692544</id><published>2010-12-05T14:10:00.001-05:00</published><updated>2011-11-24T14:32:59.288-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu Packages Please Get Your Act Together</title><content type='html'>I didn't intend to write another blog entry so close to the conclusion of my &lt;a href="http://zaemis.blogspot.com/2010/11/week-with-golang-day-1.html"&gt;Week with Go&lt;/a&gt; series, but my experiences earlier today definitely warranted a rant. Installing the SpiderMonkey JavaScript engine for use as a stand-alone interpreter on Ubuntu 10.04 LTS doesn't sound like outlandish goal. After all, CouchDB ships &lt;a href="http://www.linux-magazine.com/Online/News/Relaxed-Ubuntu-9.10-CouchDB-to-be-Integrated"&gt;by default as of 9.10&lt;/a&gt; and it requires a JavaScript run-time. Technologies like node.js and v8 are pretty hot right now so there might even be a few alternatives to choose from, right? WRONG!&lt;br /&gt;&lt;pre&gt;sudo apt-get install spidermonkey-bin&lt;br /&gt;E: Couldn't find package spidermonkey-bin&lt;/pre&gt;There used to be &lt;a href="http://packages.ubuntu.com/karmic/spidermonkey-bin"&gt;such a package&lt;/a&gt; but apparently SpiderMonkey is "unsupported" now and was removed from the Universe repository.&lt;br /&gt;&lt;br /&gt;Sorry Ubuntu. I'm not feeling the love for Rhino. It doesn't do JIT and runs slower than a one-legged sloth. Besides, I don't feel like installing &lt;tt&gt;ca-certificates-java&lt;/tt&gt;, &lt;tt&gt;default-jre-headless&lt;/tt&gt;, &lt;tt&gt;icedtea-6-jre-cacao&lt;/tt&gt;, &lt;tt&gt;java-common&lt;/tt&gt;, &lt;tt&gt;libavahi-client3&lt;/tt&gt;, &lt;tt&gt;libavahi-common-data&lt;/tt&gt;, &lt;tt&gt;libavahi-common3&lt;/tt&gt;, &lt;tt&gt;libcups2&lt;/tt&gt;, &lt;tt&gt;libjline-java&lt;/tt&gt;, &lt;tt&gt;liblcms1&lt;/tt&gt;, &lt;tt&gt;libnspr4-0d&lt;/tt&gt;, &lt;tt&gt;libnss3-1d&lt;/tt&gt;, &lt;tt&gt;openjdk-6-jre-headless&lt;/tt&gt;, &lt;tt&gt;openjdk-6-jre-lib&lt;/tt&gt;, and &lt;tt&gt;tzdata-java&lt;/tt&gt; on my system.&lt;br /&gt;&lt;br /&gt;I thought about installing it &lt;a href="http://hg.mozilla.org/mozilla-central/file/bfec67c46b7c/js"&gt;from source&lt;/a&gt; but then I'd lose the benefits all the experts say I get from using packages*. After a bit of searching I found &lt;a href="https://bugs.launchpad.net/ubuntu/+source/xulrunner-1.9.2/+bug/536950"&gt;some developer&lt;/a&gt; rolled a package that is available from a &lt;a href="https://edge.launchpad.net/~launchpad/+archive/ppa"&gt;Launchpad PPA&lt;/a&gt;, so all I'd have to do is just add the repository!&lt;br /&gt;&lt;pre&gt;$ sudo add-apt-repository ppa:launchpad/ppa&lt;br /&gt;sudo: add-apt-repository: command not found&lt;/pre&gt;Sigh. add-apt-repository is provided by the package &lt;a href="http://packages.ubuntu.com/lucid/all/python-software-properties/filelist"&gt;python-software-properties&lt;/a&gt;. The intuitiveness of it all is underwhelming.&lt;br /&gt;&lt;br /&gt;It's great that PPAs exist and people volunteer their time to maintain them to fill the gap, but Ubuntu needs to pull its head out of its ass and get its act together. Ubuntu gained popularity because people were pissed at Red Hat, not by emulating OSX with moving its close buttons, adding boring purple artwork, or the Dropbox rip-off called Ubuntu One. It needs to focus on solving real problems, like developing better package identification/search solutions, finding better ways to convey information and their rational when dropping support for packages, and making the &lt;i&gt;entire&lt;/i&gt; system user-friendly. If Ubuntu keeps disrespecting the needs of its user base then it's only a matter of time until the popularity-torch is passed to another distro. &lt;br /&gt;&lt;br /&gt;&lt;small&gt;* Benefits include unexpected dropped support, irrelevant dependencies and symlinks puked all over the system, inconsistent packaging conventions, headaches, dry-mouth, and an occasional ulcer.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5330679870314692544?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5330679870314692544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/12/ubuntu-packaging-please-get-your-act.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5330679870314692544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5330679870314692544'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/12/ubuntu-packaging-please-get-your-act.html' title='Ubuntu Packages Please Get Your Act Together'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-4092133295632933832</id><published>2010-12-03T00:01:00.002-05:00</published><updated>2011-07-10T02:06:00.636-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Golang'/><title type='text'>A Week with Go, Day 5</title><content type='html'>Concurrent programming in Go makes use of coroutines, which are quaintly called "goroutines", and channels. Coroutines are functions executed asynchronously from the rest of your program, and channels are synchronous pipes through which the routines communicate. I had written a multi-threaded &lt;a href="http://zaemis.blogspot.com/2009/06/kember-identity.html"&gt;Kember Identity&lt;/a&gt; program in C a while back, and decided to rewrite it in Go to gain some exposure working with these features.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://golang.org/doc/effective_go.html#goroutines"&gt;Effective Go primer&lt;/a&gt; gives a hint of what goes on under the hood with coroutines in Go.&lt;br /&gt;&lt;blockquote&gt;A goroutine has a simple model: it is a function executing in parallel with other goroutines in the same address space. It is lightweight, costing little more than the allocation of stack space. And the stacks start small, so they are cheap, and grow by allocating (and freeing) heap storage as required.&lt;br /&gt;&lt;br /&gt;Goroutines are multiplexed onto multiple OS threads so if one should block, such as while waiting for I/O, others continue to run. Their design hides many of the complexities of thread creation and management.&lt;/blockquote&gt;Indeed, Go does a wonderful job of hiding the complexities of working with threads. Spawning the coroutine is as simple as prefacing the function call with &lt;tt&gt;go&lt;/tt&gt;.&lt;br /&gt;&lt;pre&gt;go kemberTest(start, tmp, ch)&lt;/pre&gt;Writing and reading values to and from a channel is done with &lt;tt&gt;&amp;lt;-&lt;/tt&gt;. Both are blocking operations, so you don't have to worry about manually fumbling with locks to synchronize routines. The primer has &lt;a href="http://golang.org/doc/effective_go.html#channels"&gt;this to say&lt;/a&gt; about channels:&lt;br /&gt;&lt;blockquote&gt;Channels combine communication—the exchange of a value—with synchronization—guaranteeing that two calculations (goroutines) are in a known state.&lt;/blockquote&gt;&lt;pre&gt;if hash == curr {&lt;br /&gt;    fmt.Println(hash)&lt;br /&gt;    ch &amp;lt;- true&lt;br /&gt;    return&lt;br /&gt;}&lt;/pre&gt;No muss, no fuss. Coroutines and channels work together to make concurrent programming a breeze! I sat down expecting to stumble through getting my threads to communicate properly, but to be honest I spent more time working out the correct type castings throughout the program than I spent on the concurrency piece.&lt;br /&gt;&lt;br /&gt;The asynchronous nature of coroutines with the synchronous nature of channels make it easy to write generators, too.&lt;br /&gt;&lt;pre&gt;func fib(ch chan int64) {&lt;br /&gt;    var a, b int64 = 1, 2&lt;br /&gt;    for {&lt;br /&gt;        ch &amp;lt;- a&lt;br /&gt;        a, b = b, a + b&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt;    ch := make(chan int64)&lt;br /&gt;    go fib(ch)&lt;br /&gt;    for i := &amp;lt;- ch; i &amp;gt; 0; i = &amp;lt;- ch {&lt;br /&gt;        fmt.Println(i)&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;After spending a week with Go I formed some good opinions and some bad opinions. The language has a dynamic feel with &lt;tt&gt;:=&lt;/tt&gt; and garbage collection which is nice, though I would have liked to have seen some more type inference being done by the compiler. An OO model that's not focused on hierarchical inheritance is a welcome change. Go is still rough around the edges and I wouldn't consider it ready to be a full-time development language for production projects just yet, but it has come quite a long way in the past year... and will undoubtedly continue to mature rapidly as an open source project.&lt;br /&gt;&lt;br /&gt;Google did a disservice to Go when the language was first released by placing so much emphasis on compilation speed. The tech pundits and skeptics were right in questioning whether the world needed yet another language just because the current ones compiled too slow. Compilation is a function of the compiler after all, so if that was really the problem then a more appropriate solution would be to write a new compiler! But the pundits were ignorant in dismissing Go and believing there was no room for a new language. They failed to see an opportunity to re-examine old beliefs and explore now constructs. Many more would have taken Go seriously out of the gate if Google and early developers had touted its OO model and goroutines/channels instead of its compilation speed.&lt;br /&gt;&lt;br /&gt;I can see myself using Go for a few side projects here and there, and perhaps larger projects in the future. Perhaps I'm just not comfortable yet with garbage collection in real-time and system-level programming yet, but I don't see it replacing my use of C; I choose C when a major need of my program is speed or memory and the unpredictable nature of a garbage collector works against those. But Go would definitely be a good choice for problems now solved using Java.&lt;br /&gt;&lt;br /&gt;Thanks for spending the week with me (and Go); feel free to share your impressions of Go in the comments below. If you're interested, here's &lt;a href="http://saltcitytech.com/blogger/kember.go.txt"&gt;my Kember Identity code&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-4092133295632933832?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/4092133295632933832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/12/week-with-golang-day-5.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4092133295632933832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4092133295632933832'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/12/week-with-golang-day-5.html' title='A Week with Go, Day 5'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2575675198501430591</id><published>2010-12-02T00:01:00.002-05:00</published><updated>2011-07-10T02:06:00.636-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Golang'/><title type='text'>A Week with Go, Day 4</title><content type='html'>Day 4 was spent learning about Go's take on object oriented programming, which I found to be a refreshing change from the likes of Java and C#. It's not type-focused; instead of relying on an object's type to know whether or not it offer certain functionality, the object will generally implement an interface. This mindset is not dissimilar to good JavaScript programming where feature detection is preferred over browser sniffing. The code doesn't care &lt;i&gt;what&lt;/i&gt; something is (browser/object), just what it &lt;i&gt;can do&lt;/i&gt; (functionality/interface).&lt;br /&gt;&lt;br /&gt;The word "object" is probably a bit misleading since Go doesn't really have them in the traditional sense. There's no need to write a class definition as in Java, nor to instantiate an object literal like JavaScript. The programmer specifies a set of functions and Go's compiler deduces the relationships.&lt;br /&gt;&lt;pre&gt;type Rectangle struct {&lt;br /&gt;    width  float&lt;br /&gt;    height float&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func (r *Rectangle) Area() float {&lt;br /&gt;    return r.width * r.height&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func (r *Rectangle) Perimeter() float {&lt;br /&gt;    return r.width*2 + r.height*2&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt;    r := new(Rectangle)&lt;br /&gt;}&lt;/pre&gt;Here the &lt;tt&gt;Rectangle&lt;/tt&gt; "object" is a pointer to a structure consisting of two floats. The &lt;tt&gt;Area()&lt;/tt&gt; function can be applied as a method against any &lt;tt&gt;Rectangle&lt;/tt&gt; to calculate an area, and the &lt;tt&gt;Perimeter()&lt;/tt&gt; function can be applied to calculate the perimeter.&lt;br /&gt;&lt;br /&gt;If I were to later specify the interface &lt;tt&gt;Shape&lt;/tt&gt; which dictated an &lt;tt&gt;Area() float&lt;/tt&gt; method and &lt;tt&gt;Perimeter() float&lt;/tt&gt; method, then any &lt;tt&gt;Rectangle&lt;/tt&gt; instances will automatically implement it. The compiler knows a &lt;tt&gt;Shape&lt;/tt&gt; can have its area and perimeter calculated. A &lt;tt&gt;Rectangle&lt;/tt&gt; can have its area and perimeter calculated; therefore, it must be a &lt;tt&gt;Shape&lt;/tt&gt;.&lt;br /&gt;&lt;pre&gt;type Shape interface {&lt;br /&gt;    Area() float&lt;br /&gt;    Perimeter() float&lt;br /&gt;}&lt;/pre&gt;I appreciate Go's rejection of Java-style type-masturbation and focus on functionality. After all, &lt;a href="http://twitter.com/dozba/status/15597998855"&gt;code is a liability, functionality is an asset&lt;/a&gt;. It looks like Go will let me focus more on writing code which provides functionality instead of code that specifies type hierarchies rivaling Jesus' lineage in the &lt;a href="http://www.biblegateway.com/passage/?search=Matthew+1&amp;version=NIV"&gt;book of Matthew&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Feel free to share your impressions of Go in the comments below and come back tomorrow for the final day's entry in the series. If you're interested, here's my &lt;a href="http://saltcitytech.com/blogger/shapes.zip"&gt;shapes code&lt;/a&gt; with with &lt;tt&gt;Rectangle&lt;/tt&gt; and &lt;tt&gt;Circle&lt;/tt&gt; objects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2575675198501430591?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2575675198501430591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/12/week-with-golang-day-4.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2575675198501430591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2575675198501430591'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/12/week-with-golang-day-4.html' title='A Week with Go, Day 4'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8969428825280540264</id><published>2010-12-01T00:01:00.003-05:00</published><updated>2011-07-10T02:06:00.637-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Golang'/><title type='text'>A Week with Go, Day 3</title><content type='html'>The first two days of tinkering and scouring helped me form an opinion of Go based on its syntax. To form a more-informed opinion I would have to write some more code and see how much resistance I experienced along the way. What features were missing? How was typing applied? I wrote a rudimentary version of &lt;a href="http://en.wikipedia.org/wiki/Deal_or_No_Deal"&gt;Deal or No Deal&lt;/a&gt;, and slowly some of those meaningless sections in the language spec started taking on more meaning.&lt;br /&gt;&lt;br /&gt;I decided to store the case amounts as an integer array (nobody likes the 0.01 anyway!) and came across my first bit of frustration and misunderstanding when it came time to shuffle the amounts.&lt;br /&gt;&lt;pre&gt;cases = []int{100, 200, 300, 400, 500, 750, 1000,&lt;br /&gt;    5000, 10000, 50000}&lt;br /&gt;shuffle(cases)&lt;br /&gt;&lt;br /&gt;func shuffle(arr []int) {&lt;br /&gt;        rand.Seed(time.Nanoseconds())&lt;br /&gt;        for i := len(arr) - 1; i &amp;gt; 0; i-- {&lt;br /&gt;                j := rand.Intn(i)&lt;br /&gt;                arr[i], arr[j] = arr[j], arr[i]&lt;br /&gt;        }&lt;br /&gt;}&lt;/pre&gt;The language spec says arrays are value types and slices are reference types. &lt;tt&gt;shuffle&lt;/tt&gt; was doing what I wanted, but why was Go manipulating the array values if &lt;tt&gt;cases&lt;/tt&gt; was supposed to be passed by value? I &lt;a href="http://stackoverflow.com/questions/4221698/treatment-of-arrays-in-go"&gt;posted the question on Stack Overflow&lt;/a&gt; and it became clear that &lt;tt&gt;cases&lt;/tt&gt; was a slice. I had written &lt;tt&gt;[]int{}&lt;/tt&gt; expecting the behavior of &lt;tt&gt;[...]int{}&lt;/tt&gt;. Hopefully this will be the first and last time I make this mistake, but I have a feeling it won't be even with a correct understanding of what Go is doing. The syntax is just too similar. I don't understand why almost identical syntax was chosen for two different concepts here but different syntax was chosen for identical concepts with &lt;tt&gt;var =&lt;/tt&gt; vs &lt;tt&gt;:=&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;And I was lucky I only needed to shuffle a list of integer values; Go doesn't have generics, so I wouldn't be able to easily write a general-purpose shuffle function. It feels "dirty" to write &lt;tt&gt;&lt;nobr&gt;shufflei(arr&lt;/nobr&gt; &lt;nobr&gt;[]int)&lt;/nobr&gt;&lt;/tt&gt;, &lt;tt&gt;&lt;nobr&gt;shufflef(arr&lt;/nobr&gt; &lt;nobr&gt;[]float)&lt;/nobr&gt;&lt;/tt&gt;, etc. since the functions would all be identical except for their signatures!&lt;br /&gt;&lt;br /&gt;The appeal of clean-looking code, novel looping, and an official formatting utility was waning because of issues and deficiencies more integral to the language and its implementation. Go is still nascent, but we shouldn't be revisiting these problems in a modern programming language.&lt;br /&gt;&lt;br /&gt;Feel free to share your impressions of Go in the comments below and come back tomorrow for day 4. If you're interested, here's my &lt;a href="http://saltcitytech.com/blogger/dond.go.txt"&gt;Deal or No Deal code&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8969428825280540264?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8969428825280540264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/12/week-with-golang-day-3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8969428825280540264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8969428825280540264'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/12/week-with-golang-day-3.html' title='A Week with Go, Day 3'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2775870019520182635</id><published>2010-11-30T00:01:00.001-05:00</published><updated>2011-07-10T02:06:00.638-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Golang'/><title type='text'>A Week with Go, Day 2</title><content type='html'>After dabbling a little bit on day 1, I dedicated some time on day 2 to skim through Go's &lt;a href="http://golang.org/doc/go_spec.html"&gt;language spec&lt;/a&gt; and &lt;a href="http://golang.org/pkg/"&gt;standard libraries&lt;/a&gt;. A lot of it didn't have much relevance to me yet because I hadn't begun to play with those parts of the language. What caught my eye though was that Go supports the &lt;tt&gt;\v&lt;/tt&gt; escape (obviously no one at Google has read &lt;a href="http://prog21.dadgum.com/76.html"&gt;Stop the Vertical Tab Madness&lt;/a&gt;). Welcome to 1963, folks.&lt;br /&gt;&lt;br /&gt;In addition to tweaking how loops are written, Go has augmented the traditional syntax of &lt;tt&gt;if&lt;/tt&gt; and &lt;tt&gt;switch&lt;/tt&gt; statements too. I don't see the enhancement providing as much benefit as I do with &lt;tt&gt;for&lt;/tt&gt;. It's almost as if someone decided to let people move the placement of &lt;tt&gt;if&lt;/tt&gt; up a statement earlier just to be different, and it certainly doesn't read well.&lt;br /&gt;&lt;pre&gt;x := recover()&lt;br /&gt;if x != nil { ... }&lt;/pre&gt;vs&lt;br /&gt;&lt;pre&gt;if x := recover(); x != nil { ... }&lt;/pre&gt;&lt;br /&gt;The list of available packages is rather impressive considering Go has been available for a year. Some packages are pretty standard, like &lt;a href="http://golang.org/pkg/math/"&gt;math&lt;/a&gt; and &lt;a href="http://golang.org/pkg/cmath/"&gt;cmath&lt;/a&gt;, while some other packages like &lt;a href="http://golang.org/pkg/patch/"&gt;patch&lt;/a&gt;, &lt;a href="http://golang.org/pkg/ebnf/"&gt;ebnf&lt;/a&gt;, and &lt;a href="http://golang.org/pkg/tabwriter/"&gt;tabwriter&lt;/a&gt; look more intriguing. The &lt;a href="http://golang.org/pkg/regexp/"&gt;regexp&lt;/a&gt; and &lt;a href="http://golang.org/pkg/rand/"&gt;rand&lt;/a&gt; packages look to me a bit bloated and could stand to be pared down a bit, regexp especially since Go allows multiple return values from functions; maybe someone just got API happy.&lt;br /&gt;&lt;br /&gt;There's also a utility named &lt;a href="http://golang.org/cmd/gofmt/"&gt;gofmt&lt;/a&gt; which is used to format Go code. It serves as the official style guidelines in an attempt to avoid code formatting wars. I don't agree with some of their choices, but that only highlights the usefulness of gofmt. More languages should ship with such a utility officially. gofmt can also be used as a sort of lint application since it can't properly format code with syntax errors.&lt;br /&gt;&lt;br /&gt;The selection of library packages for Go will hopefully continue to grow over time, and a tool like gofmt is nice to have in your arsenal. I'm still thinking favorably of Go after the second day.&lt;br /&gt;&lt;br /&gt;Feel free to share your impressions of Go in the comments below and come back tomorrow for day 3.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2775870019520182635?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2775870019520182635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/11/week-with-golang-day-2.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2775870019520182635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2775870019520182635'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/11/week-with-golang-day-2.html' title='A Week with Go, Day 2'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2434861008408029138</id><published>2010-11-29T00:01:00.002-05:00</published><updated>2011-07-10T02:06:00.638-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Golang'/><title type='text'>A Week with Go, Day 1</title><content type='html'>&lt;a href="http://golang.org/"&gt;Go&lt;/a&gt; is a general purpose systems programming language developed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. Go has been on my radar since it became publicly available a year ago as an open source project, and since then its documentation has been improving and a small community of users has been forming around the language. Last week I had some time off from work that coincided nicely with the Thanksgiving holiday and I thought it'd be fun to spend some of it looking at Go. Here's the first in a series of five posts that share my thoughts and experiences of spending a week with Go.&lt;br /&gt;&lt;br /&gt;My first Go programs were solutions to a couple &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; solutions. This was just to get a basic feel for its syntax.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Problem 1&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;package main&lt;br /&gt;&lt;br /&gt;import fmt "fmt"&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt;    sum := 0&lt;br /&gt;    for i := 0; i &amp;lt; 1000; i++ {&lt;br /&gt;        if i%3 == 0 || i%5 == 0 {&lt;br /&gt;            sum += i&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    fmt.Printf("%d\n", sum)&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;There are a few oddities, but overall there's nothing earth shattering with Go's syntax.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Parentheses aren't used in constructs like &lt;tt&gt;if&lt;/tt&gt; and &lt;tt&gt;for&lt;/tt&gt; as they are in C, though braces are always required, and semicolons are used as separators-- not terminators. The resulting code looks nice and clean. The lack of terminators is a bit disconcerting, though... have we learned nothing from &lt;a href="http://javascript.crockford.com/code.html"&gt;JavaScript&lt;/a&gt;?&lt;/li&gt;&lt;li&gt;&lt;tt&gt;:=&lt;/tt&gt; elides variable declarations and the compiler will deduce the variable's type, reminiscent of OCaml's type inference (though it doesn't extend to function declarations and the like). The more verbose way of declaring and assigning &lt;tt&gt;sum&lt;/tt&gt; would be &lt;tt&gt;var sum int = 0&lt;/tt&gt;. It's nice once you get the hang of it, but I think this might be a bit confusing for new programmers.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Problem 2&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;package main&lt;br /&gt;&lt;br /&gt;import fmt "fmt"&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt;    a, b, c, sum := 0, 1, 0, 0&lt;br /&gt;    for c &amp;lt; 4000000 {&lt;br /&gt;        c = a + b&lt;br /&gt;        a, b = b, c&lt;br /&gt;&lt;br /&gt;        if c%2 == 0 {&lt;br /&gt;            sum += c&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    fmt.Printf("%d\n", sum)&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Whoa, Go doesn't have a while loop? Surely this is madness!&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The designers extended the minimal syntax philosophy to common language constructs as well. Different &lt;tt&gt;for&lt;/tt&gt; variations are used to write not only your traditional &lt;tt&gt;for&lt;/tt&gt; loops, but also &lt;tt&gt;while&lt;/tt&gt; loops and &lt;tt&gt;foreach&lt;/tt&gt;/&lt;tt&gt;for in&lt;/tt&gt; loops. I think &lt;tt&gt;for c &amp;lt; 4000000&lt;/tt&gt; is a bit awkward to read but it becomes second nature to write in short order.&lt;/li&gt;&lt;/ul&gt;It's nice to have less keywords and the code looks clean and readable. Despite some hesitance, my opinion was favorable overall after the first day.&lt;br /&gt;&lt;br /&gt;Feel free to share your impressions of Go in the comments below and come back tomorrow for day 2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2434861008408029138?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2434861008408029138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/11/week-with-golang-day-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2434861008408029138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2434861008408029138'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/11/week-with-golang-day-1.html' title='A Week with Go, Day 1'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-1470021747977106424</id><published>2010-11-16T16:50:00.006-05:00</published><updated>2010-11-16T19:56:38.066-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><category scheme='http://www.blogger.com/atom/ns#' term='Predictions'/><title type='text'>On Gartner's 2011 Top Technologies</title><content type='html'>A coworker stumbled across &lt;a href="http://blogs.techrepublic.com.com/10things/?p=1871&amp;amp;tag=nl.e101"&gt;Gartner's top 10 technologies for 2011&lt;/a&gt; and decided to share it with everyone in the office via email. Overlooking the need for a &lt;a href="http://www.urbandictionary.com/define.php?term=cluebat"&gt;cluebat&lt;/a&gt;, and resisting the urge to similarly spam everyone with &lt;a href="http://theoatmeal.com/comics/email"&gt;The Oatmeal's take on email etiquette&lt;/a&gt;, I think Gartner missed the mark on some things.&lt;br /&gt;&lt;br /&gt;Let's be honest for a moment. Cloud computing has been hyped since '08 when &lt;a href="http://www.eucalyptus.com/"&gt;Eucalyptus&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud"&gt;Amazon's EC2 Services&lt;/a&gt; came out. Social media has been on the radar since since blogs became popular (though admittedly Twitter and Facebook upped the ante). Mobile computing has been slowly making inroads but I think it's still too soon to claim "The PC era is over." All the technologies have been around for years in one form or another; they just happen to be "hot" right now... and by the time someone starts touting them they've probably peaked.&lt;br /&gt;&lt;br /&gt;In the next 12 months I predict there'll be a lot of potential for things like IPv4/6 networking, JavaScript, Flash, and whatever comes out of the &lt;a href="http://www.webpronews.com/topnews/2010/11/15/hitwise-supplies-info-on-possible-google-facebook-email-fight"&gt;Facebook v. Google storm&lt;/a&gt; that's brewing. I may be wrong... but hindsight is 20/20 so I guess I'll just have to make a few of my own predictions here and see how on the mark I was come next November.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Networking&lt;/b&gt;&lt;br /&gt;IPv6 hasn't seen widespread adoption despite being standardized for over 10 years. Supposedly &lt;a href="http://www.guardian.co.uk/technology/2010/nov/11/google-vint-cerf-internet"&gt;Europe is running thin on the IPv4 front&lt;/a&gt; with something like 4% of the address-space left, and getting down to around 1-1.5% might be enough to force the ISPs and TELCOs to start investing more in their infrastructure. Either that, or perhaps someone will devise a creative way to prolong the inevitable either with some new NAT/routing extensions, or a new backwards-compatible protocol obsoleting IPv6 that would overlay nicely on IPv4 to allow backwards compatibility and future growth (along the lines of how 64-bit processor registers extended their 32-bit registers, which in turn extended their 16-bit registers, etc).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JavaScript&lt;/b&gt;&lt;br /&gt;Developers are finally starting to fully explore JavaScript's capabilities, are becoming more comfortable with duck-typing, and Google's V8 engine has done pretty well in speeding up JavaScript's execution, to the point where I can see more and more programmers attempting serious server-side programming in JavaScript. &lt;a href="http://research.nihonsoft.org/javascript/ServerGuideJS12/index.htm"&gt;Server-Side JavaScript&lt;/a&gt; is nothing new, but if one or two start-ups can make it big within the next year or so using a technology stack focused on server-side JavaScript, it may make others in the market comfortable enough to take the plunge themselves... if not in 2011, then possibly 2012. This would be thanks in no small part to &lt;a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"&gt;ECMA-262&lt;/a&gt;'s strict mode in an attempt to clean some cruft from the language, and projects like &lt;a href="http://www.commonjs.org/"&gt;CommonJS&lt;/a&gt; and &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;. I only hope it doesn't get bastardized with Java-like public/private syntax in the process.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;HTML5/Flash&lt;/b&gt;&lt;br /&gt;I think HTML5 is a lot of fluff-- the &lt;a href="http://ishtml5readyyet.com/"&gt;standard isn't expected to be completed&lt;/a&gt; until 2020ish, and technology moves so fast now that by then it'll be irrelevant. Browsers and developers are trying to be early adopters so they can be the cool kids on the block, but let's face it... the multimedia developer is going to prefer something like Flash to create their website experiences in than programing JavaScript code in an IDE; synchronizing timers to manipulate objects and sounds is easier with a click/drag-and-drop interface. JavaScript will be big with programmers/back-end developers, but if Adobe can re-align the Flash product and address some of the memory usage concerns, they can come out on top with the front-end/multimedia folks. Apple won't suffer, but people will &lt;a href="http://www.apple.com/hotnews/thoughts-on-flash/"&gt;see through their arguments&lt;/a&gt; for what they are-- self-preservation and vendor lock-in efforts.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Social Media&lt;/b&gt;&lt;br /&gt;There's a turf war simmering between Facebook and Google that could have interesting repercussions for the rest of us. Facebook is rolling out new a new email-type feature to make communication with non-facebookers easier and to consolidate/streamline the social media experience, which looks similar to &lt;a href="http://www.readwriteweb.com/archives/google_wave_is_dead.php"&gt;Google's failed Facebook-killer Wave product&lt;/a&gt; with a less-crappy interface. Google is suddenly &lt;a href="http://www.wired.com/epicenter/2010/11/google-trap-my-data-snark/"&gt;concerned with defending&lt;/a&gt; our rights when it comes to &lt;i&gt;our&lt;/i&gt; own content. I can imagine a spirited debate on privacy, ownership, and copyrights in the 21st century.&lt;br /&gt;&lt;br /&gt;Then there's the question of how can a CEO take advantage of these changes in technology and the tech/social landscape to increase their company's profits. Since we're being honest with one another, I can say I don't know and not feel too bad about it. If I did know, I wouldn't be blogging about it here; I'd be out positioning myself to be the next Gates, Page, or Zuckerberg. Maybe there will be some new startup mash-up type service providers (like &lt;a href="http://www.qwiki.com/"&gt;qwiki.com&lt;/a&gt; only not as annoying?) that will spring up which will eventually turn to targeted advertising for their revenue. Or, wouldn't it be nice if someone came up with a product/service to make parents be responsible and &lt;a href="http://www.syracuse.com/news/index.ssf/2010/11/anti-violence_vigil_ends_when.html"&gt;not raise douche-bag children&lt;/a&gt;, for it to be cool for kids to put down their cell phones and mp3 players and eat dinner at the table as a family, and maybe spread a little inter-office email etiquette just for good measure?&lt;br /&gt;&lt;br /&gt;Just my thoughts...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-1470021747977106424?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/1470021747977106424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/11/on-gartners-2011-top-technologies.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1470021747977106424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1470021747977106424'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/11/on-gartners-2011-top-technologies.html' title='On Gartner&apos;s 2011 Top Technologies'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-7594395539363531360</id><published>2010-11-10T22:52:00.001-05:00</published><updated>2011-06-04T18:26:30.976-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Perl'/><title type='text'>"Inchworm on a Stick" in PHP</title><content type='html'>&lt;tt&gt;~-&lt;/tt&gt; is known as the &lt;a href="http://www.catonmat.net/blog/secret-perl-operators/#inchwormstick"&gt;inchworm on a stick operator&lt;/a&gt; in Perl obfuscation circles. It isn't really an operator; it's a term coined to describe negating a value and then taking its compliment, the apparent effect of which is to decrement the value. (To understand why, you need to understand how &lt;a href="http://en.wikipedia.org/wiki/Two%27s_complement"&gt;negative numbers are represented&lt;/a&gt; in binary.)&lt;br /&gt;&lt;br /&gt;In Perl, &lt;tt&gt;~-&lt;/tt&gt; works for positive values:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;for ($i = 3; $i &amp;gt; -3; $i--) {&lt;br /&gt;    print ~-$i . "\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$ perl test.pl&lt;br /&gt;2&lt;br /&gt;1&lt;br /&gt;0&lt;br /&gt;4294967295&lt;br /&gt;4294967294&lt;br /&gt;4294967293&lt;/pre&gt;&lt;br /&gt;Interestingly enough, when the same is tried in PHP the results are slightly different...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;2&lt;br /&gt;1&lt;br /&gt;0&lt;br /&gt;-1&lt;br /&gt;-2&lt;br /&gt;-3&lt;/pre&gt;&lt;br /&gt;PHP treats the value as a signed integer where Perl treats it as an unsigned integer. I don't know which way is "better" or which is "more correct," but it is something I found interesting and I thought would be worth sharing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-7594395539363531360?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/7594395539363531360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/11/inchworm-on-stick-in-php.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7594395539363531360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7594395539363531360'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/11/inchworm-on-stick-in-php.html' title='&quot;Inchworm on a Stick&quot; in PHP'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5344476724364577504</id><published>2010-10-02T22:38:00.014-04:00</published><updated>2010-10-24T14:06:05.086-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>8 Tips to Improve Your Golf Game</title><content type='html'>I wasted more time golfing this week than I should have. No, not real golf... &lt;a href="http://codegolf.com/"&gt;code golf&lt;/a&gt;. Trying to write small programs in the least number of keystrokes can be fun, challenging, and sometimes even addicting. It's not about writing pretty code or code that's easily-understandable. It's all about cramming as much code as you can into the least number of characters. While &lt;a href="http://www.golfscript.com/golfscript/"&gt;some languages&lt;/a&gt; golf better than others, you can still write impressively small code in your language of choice if you're familiar enough with the intricacies of its behavior. Here are 8 tips to improve your golf score when golfing with PHP:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Use short tags.&lt;/b&gt;&lt;br /&gt;Using &lt;tt&gt;&amp;lt;?&lt;/tt&gt; instead of &lt;tt&gt;&amp;lt;?php&lt;/tt&gt; and using &lt;tt&gt;&amp;lt;?=&lt;/tt&gt; instead of &lt;tt&gt;&amp;lt;?echo&lt;/tt&gt; will both save you 3 characters.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Avoid initializing variables if possible.&lt;/b&gt;&lt;br /&gt;Uninitialized variables assume the value &lt;tt&gt;0&lt;/tt&gt;, &lt;tt&gt;""&lt;/tt&gt;, or &lt;tt&gt;false&lt;/tt&gt; depending on the context in which they're referenced. &lt;tt&gt;$x=0;&lt;/tt&gt; is 5 characters too much!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Know your function aliases.&lt;/b&gt;&lt;br /&gt;A few functions in PHP are known by multiple names. &lt;tt&gt;join()&lt;/tt&gt; for example is 3 characters shorter than &lt;tt&gt;implode()&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Don't repeat yourself unnecessarily.&lt;/b&gt;&lt;br /&gt;Consider saving the name of an oft-used function to a variable if you use the function more than once, but the function name needs to be more than 4 characters and used at least twice for any savings. &lt;tt&gt;$c=chop;$c($a);$c($b);&lt;/tt&gt; is actually 4 characters more than just calling &lt;tt&gt;chop()&lt;/tt&gt; twice.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Love bare literals.&lt;/b&gt;&lt;br /&gt;PHP treats bare literals as strings, so you can save 2 characters by dropping the quotation marks.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Don't love bare literals.&lt;/b&gt;*&lt;br /&gt;Use bit negation and binary string literals to save an extra character. &lt;tt&gt;~ß&lt;/tt&gt; is better than &lt;tt&gt;" "&lt;/tt&gt;, and &lt;tt&gt;~ő&lt;/tt&gt; is definitely better than &lt;tt&gt;"\n"&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Take advantage of side effects.&lt;/b&gt;&lt;br /&gt;Something like &lt;tt&gt;$b=1;$x=80;&lt;/tt&gt;, where &lt;tt&gt;$b&lt;/tt&gt; is acting as a Boolean, might be written as &lt;tt&gt;$b=$x=80;&lt;/tt&gt;. &lt;tt&gt;$x&lt;/tt&gt; is assigned 80 and then assignment operator returns that value, which is then assigned to &lt;tt&gt;$b&lt;/tt&gt;. Non-zero integers are considered &lt;tt&gt;true&lt;/tt&gt;, so the two are semantically equivalent with a savings of 2 characters. Another example is &lt;tt&gt;echo$x--,"bottles of beer";&lt;/tt&gt;, which is shorter than &lt;tt&gt;echo"$x bottles of beer";$x--;&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reduce incrementally.&lt;/b&gt;&lt;br /&gt;Write non-golf code first to make sure you fully understand the problem &lt;i&gt;and&lt;/i&gt; your solution, then rework your code smaller and smaller in incremental steps. Don't forget to verify its correctness after each reduction.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Consider different approaches to solving the problem.&lt;/b&gt;&lt;br /&gt;You might think to choose an array if you need a sequence of character values accessible by a numeric index, but storing them as a string might be just as effective. Then again, it may not depending on how that choice affects how you work with the data later. Don't hesitate to try both approaches to see where they lead you.&lt;br /&gt;&lt;br /&gt;&lt;small&gt;* Don't... negation... get it? Ha ha! Yeah, don't worry. I won't quit my day job.&lt;/small&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://codegolf.com/saving-time"&gt;&lt;img border="0" src="http://lh4.ggpht.com/_seHKqAQg2nk/TMR1W8CEptI/AAAAAAAAANU/mfjuaMtRihg/5th.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5344476724364577504?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5344476724364577504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/10/8-tips-to-improve-your-golf-game.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5344476724364577504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5344476724364577504'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/10/8-tips-to-improve-your-golf-game.html' title='8 Tips to Improve Your Golf Game'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_seHKqAQg2nk/TMR1W8CEptI/AAAAAAAAANU/mfjuaMtRihg/s72-c/5th.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8713184494406625325</id><published>2010-08-19T22:42:00.024-04:00</published><updated>2011-06-30T16:24:29.106-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>I Remember...</title><content type='html'>I remember when Java first came out surfing the Internet on my 28k dial-up connection and &lt;a href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1201-soapbox.html"&gt;hitting a page with a Java applet&lt;/a&gt;; either Netscape would &lt;a href="http://www.cigital.com/hostile-applets/"&gt;come crashing down &lt;/a&gt;or my computer would lock up...&lt;br /&gt;&lt;br /&gt;I remember schoolmates telling me Java was "the future" because it ran on a virtual machine which meant it was cross platform, and then being ostracized  by them when I pointed out that &lt;a href="http://en.wikipedia.org/wiki/QBasic"&gt;QBasic would be considered cross platform&lt;/a&gt;, too...&lt;br /&gt;&lt;br /&gt;I remember reading Java programming books before I understood OOP and wondering why I had to write a hundred lines of code &lt;a href="http://www.roseindia.net/java/beginners/Applet.shtml"&gt;just to output "Hello World"&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;I remember reading Java programming books &lt;span style="font-style: italic;"&gt;after&lt;/span&gt; I understood OOP and still wondering why I had to write a hundred lines of code just to output "Hello World"...&lt;br /&gt;&lt;br /&gt;I remember trying to convince myself every time I started Eclipse and watched my &lt;a href="http://www.eclipsezone.com/eclipse/forums/t73716.html"&gt;P4 run slower than a 486&lt;/a&gt; that I just hadn't given Java a fair shake and I needed to embrace it with an open heart and mind...&lt;br /&gt;&lt;br /&gt;I remember working a contract-gig on a government funded Java web-based application and trudging through spaghetti code &lt;a href="http://www.codinghorror.com/blog/2004/12/it-came-from-planet-architecture.html"&gt;they claimed was design patterns&lt;/a&gt; and infinity-tier architecture they claimed was best practices...&lt;br /&gt;&lt;br /&gt;I remember learning &lt;a href="http://www.darksleep.com/player/JavaAndUnsignedTypes.html"&gt;unsigned integers are for losers&lt;/a&gt;, and Java is a programming language for winners; no one will ever need an unsigned 64-bit integer anyway...&lt;br /&gt;&lt;br /&gt;I remember reading licensing clauses that &lt;a href="http://www.java.com/en/download/license.jsp"&gt;prohibit using Java&lt;/a&gt; to build critical software to &lt;a href="http://yakovfain.javadevelopersjournal.com/java_failure_can_lead_to_death.htm"&gt;monitor things like nuclear reactors&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;I remember seeing the &lt;a href="http://www.flickr.com/photos/tychay/1388234558/"&gt;"Life is too short for Java" t-shirt&lt;/a&gt; and feeling I was a horrible person because I sympathized with it...&lt;br /&gt;&lt;br /&gt;I remember refusing to apply for a Java programming job,  much to my parents' dismay and lecturing because I was unemployed, and instead starting &lt;a href="http://www.saltcitytech.com/"&gt;my first business venture&lt;/a&gt;, &lt;a href="http://www.amazon.com/PHP-MySQL-Create-Modify-Reuse/dp/0470192429"&gt;writing my first book&lt;/a&gt;, and landing a full-time job using a language I enjoy...&lt;br /&gt;&lt;br /&gt;I remember Sun's only way of making a profit off Java was &lt;a href="http://tirania.org/blog/archive/2010/Aug-13.html"&gt;suing business partners&lt;/a&gt; they had previously licensed its use to...&lt;br /&gt;&lt;br /&gt;With such sweet memories, why can't I remember why I hate Java?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8713184494406625325?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8713184494406625325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/08/i-remember.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8713184494406625325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8713184494406625325'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/08/i-remember.html' title='I Remember...'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2642135317957953176</id><published>2010-07-25T23:09:00.005-04:00</published><updated>2011-06-30T00:53:23.951-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>End of Support isn't the End of the World</title><content type='html'>The PHP development team &lt;a href="http://www.php.net/archive/2010.php#id2010-07-22-1"&gt;released PHP 5.2.14&lt;/a&gt; last week and with it comes the end of active support for the 5.2 branch. A &lt;a href="http://blog.tabini.ca/2010/07/php-5-2-support-ends-just-as-its-adoption-begins/"&gt;bit of dissent&lt;/a&gt; rippled throughout the community... but is it really a big deal? Contrary to popular belief, downloads from php.net don't come with an expiration date.&lt;br /&gt;&lt;br /&gt;There is a lot of legacy code running mission-critical applications.  These apps work and are stable so the time, effort, and expense required to upgrade them put doing so very low on a companies' priority lists. A few years ago I worked as a System Administrator for a credit union turned bank; the core processing system was &lt;a href="http://www.fisolutionswiki.com/wiki/index.php?title=Symitar_%28Jack_Henry%29"&gt;written in PL/I&lt;/a&gt; and the ATM switching system was &lt;a href="http://www.csfi.com/Files/VOLTDS%20Brochure.pdf"&gt;written in COBOL&lt;/a&gt;. There are probably more applications written in non-OOP PHP 3 code with register globals running atop a Linux 2.4 kernel than any of us want to acknowledge.&lt;br /&gt;&lt;br /&gt;But version numbers are just mile-markers that reference a snapshot of the project at a given time. The development team is continually improving PHP so there will always be a newer, better version just around the corner. If your application is running stable on whatever version you have installed, and you're not using features or extensions that are subject to security or bug fixes in newer versions, then what's the problem? Use the version that works for you (and that your company's compliance officer &lt;a href="http://ie6list.com/"&gt;will let you use&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;With that said, don't expect the development team to support your favorite branch forever. PHP is open-source; people are free to participate in its development and do so for a variety of reasons. Just as the resources you can allot to refactoring legacy code are limited, the &lt;a href="http://twitter.com/derickr/status/19346981317"&gt;resources the development team have are limited&lt;/a&gt; as well. If you need a version 5.2.15, .16, or beyond then &lt;a href="http://phpadvent.org/2008/less-whining-more-coding-by-elizabeth-smith"&gt;get involved and make it happen&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2642135317957953176?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2642135317957953176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/07/end-of-support-isnt-end-of-world.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2642135317957953176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2642135317957953176'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/07/end-of-support-isnt-end-of-world.html' title='End of Support isn&apos;t the End of the World'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-1686712663812803382</id><published>2010-07-13T21:47:00.020-04:00</published><updated>2011-07-10T02:06:00.639-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Prolog'/><title type='text'>Learning Prolog</title><content type='html'>I'm not quite sure exactly I was searching for, but somehow I serendipitously stumbled upon the site &lt;a href="http://www.learnprolognow.org"&gt;learnprolognow.org&lt;/a&gt; a few months ago. It's the home for an introductory Prolog programming course. &lt;a href="http://en.wikipedia.org/wiki/Logic_programming"&gt;Logic programming&lt;/a&gt; offers an interesting way to think about your problems; I've been doing so much procedural and object-oriented programming in the past decade that it really took effort to think at a higher level!&lt;br /&gt;&lt;br /&gt;I found the most interesting features to be definite clause grammars (DCG), and unification. Difference lists are very powerful and Prolog's DCG syntax makes it easy to work with them. Specifying a grammar such as:&lt;br /&gt;&lt;pre&gt;s(s(NP,VP)) --&amp;gt; np(NP,X,Y,subject), vp(VP,X,Y).&lt;br /&gt;&lt;br /&gt;np(np(DET,NBAR,PP),X,Y,_) --&amp;gt; det(DET,X), nbar(NBAR,X,Y),&lt;br /&gt;  pp(PP).&lt;br /&gt;np(np(DET,NBAR),X,Y,_) --&amp;gt; det(DET,X), nbar(NBAR,X,Y).&lt;br /&gt;np(np(PRO),X,Y,Z) --&amp;gt; pro(PRO,X,Y,Z).&lt;br /&gt;&lt;br /&gt;vp(vp(V),X,Y) --&amp;gt; v(V,X,Y).&lt;br /&gt;vp(vp(V,NP),X,Y) --&amp;gt; v(V,X,Y), np(NP,_,_,object).&lt;br /&gt;&lt;br /&gt;nbar(nbar(JP),X,3) --&amp;gt; jp(JP,X).&lt;br /&gt;&lt;br /&gt;pp(pp(PREP,NP)) --&amp;gt; prep(PREP), np(NP,_,_,object).&lt;br /&gt;&lt;br /&gt;jp(N,X) --&amp;gt; n(N,X).&lt;br /&gt;jp(jp(ADJ,JP),X) --&amp;gt; adj(ADJ), jp(JP,X).&lt;br /&gt;&lt;br /&gt;det(det(DET),X) --&amp;gt; [DET], {lex(DET,det,X)}.&lt;br /&gt;&lt;br /&gt;pro(pro(PRO),X,Y,Z) --&amp;gt; [PRO], {lex(PRO,pro,X,Y,Z)}.&lt;br /&gt;&lt;br /&gt;v(v(V),X,Y) --&amp;gt; [V], {lex(V,v,X,Y)}.&lt;br /&gt;&lt;br /&gt;prep(prep(PREP)) --&amp;gt; [PREP], {lex(PREP,prep)}.&lt;br /&gt;&lt;br /&gt;n(n(N),X) --&amp;gt; [N], {lex(N,n,X)}.&lt;br /&gt;&lt;br /&gt;adj(adj(ADJ)) --&amp;gt; [ADJ], {lex(ADJ,adj)}.&lt;/pre&gt;allows me to parse a statement for grammatical correctness, produce a parse tree, and determine where the point of failure is if it isn't grammatical.&lt;br /&gt;&lt;pre&gt;?- s(X,[the,man,shoots,he],Y).&lt;br /&gt;X = s(np(det(the), nbar(n(man))), vp(v(shoots))),&lt;br /&gt;Y = [he]&lt;/pre&gt;The power of unification is highlighted by the &lt;code&gt;append/3&lt;/code&gt; predicate, a "function" whose primary purpose is to concatenate two lists. By providing partial lists and pattern structures, append can not only be used to concatenate, but also split a list, double it, and even test an element for membership.&lt;br /&gt;&lt;pre&gt;is_member(X,Y) :- append(_,[X|_],Y).&lt;br /&gt;?- is_member(4,[1,2,3,4,5]).&lt;br /&gt;Yes&lt;/pre&gt;I have to say working through the course has made me a better programmer. It exposed me to new ways of thinking about old problems which broadened my "programmer toolset." I feel more comfortable working with immutable variables and recursion, too-- both concepts which I knew but subconsciously shied away from.&lt;br /&gt;&lt;br /&gt;One of the difficulties of self-study though is the lack of teacher and classmates to ask questions and verify solutions. I purchased the &lt;a href="http://www.amazon.com/Learn-Prolog-Now-Patrick-Blackburn/dp/1904987176"&gt;printed version&lt;/a&gt; of the course to check my work but was dismayed to see it only contains answers for the chapter exercises. I've decided to make my &lt;a href="http://www.saltcitytech.com/blogger/lpn.zip"&gt;solutions to the practical sections&lt;/a&gt; available for other self-learners. &lt;br /&gt;&lt;br /&gt;I definitely recommend setting aside some spare time and working your way through the course if you haven't been exposed to Prolog somewhere in your studies or career already.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-1686712663812803382?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/1686712663812803382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/07/learning-prolog.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1686712663812803382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1686712663812803382'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/07/learning-prolog.html' title='Learning Prolog'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-4853218228762264215</id><published>2010-07-06T18:44:00.000-04:00</published><updated>2010-07-06T18:46:00.947-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>On Unobtrusive JavaScript</title><content type='html'>Traditionally, unobtrusive JavaScript means the code is kept separate from the page's markup. This separation makes it easier to maintain and reuse the code. However, I view unobtrusive code as more than simple separation. True unobtrusiveness means your JavaScript code will function alongside other code that may be loaded by the browser, and the other code will function alongside yours. Don't pollute the global scope in the execution environment; don't clobber global objects, their properties, or prototypes with your own; and be able to work alongside various frameworks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-4853218228762264215?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/4853218228762264215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/07/on-unobtrusive-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4853218228762264215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4853218228762264215'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/07/on-unobtrusive-javascript.html' title='On Unobtrusive JavaScript'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-434246070166465327</id><published>2010-05-01T16:26:00.007-04:00</published><updated>2010-05-01T23:13:59.635-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='C#/.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Use Discretion when Reviewing Code Metrics</title><content type='html'>Code metrics are interesting creatures.  Some are just raw numbers, such as depth of inheritance or lines of code, while others are a bit more subjective, like a maintainability index. But ultimately they are all meaningless without broader context and an understanding of the code.&lt;br /&gt;&lt;br /&gt;As a brief example, consider the following C# function which accepts a string and returns the 40-character hexadecimal representation of the string's &lt;a href="http://www.faqs.org/rfcs/rfc3174"&gt;SHA1 hash&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public static String Sha1(String text)&lt;br /&gt;{&lt;br /&gt;    using (SHA1Managed sha1 = new SHA1Managed())&lt;br /&gt;    {&lt;br /&gt;        Byte[] textBytes = Encoding.Unicode.GetBytes(text);&lt;br /&gt;        Byte[] hashBytes = sha1.ComputeHash(textBytes);&lt;br /&gt;        return Convert.ToBase64String(hashBytes);   &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The function accomplishes one task. Variables are defined closest to their usage. Function calls are clear and do not nest other function calls.  Even using ( ) is used so the run-time can automatically dispose of the SHA1Managed resource. Yet a scan using &lt;a href="http://zaemis.blogspot.com/2010/04/visual-studio-2010-released.html"&gt;Visual Studio 2010&lt;/a&gt;'s Code Metrics returns a maintainability index of 71.&lt;br /&gt;&lt;br /&gt;The index increases to 73 when the definition of variables move outside of the using ( ) block.&lt;br /&gt;&lt;pre&gt;public static String Sha1(String text)&lt;br /&gt;{&lt;br /&gt;    Byte[] textBytes, hashBytes;&lt;br /&gt;    using (SHA1Managed sha1 = new SHA1Managed())&lt;br /&gt;    {&lt;br /&gt;        textBytes = Encoding.Unicode.GetBytes(text);&lt;br /&gt;        hashBytes = sha1.ComputeHash(textBytes);&lt;br /&gt;    }&lt;br /&gt;    return Convert.ToBase64String(hashBytes);  &lt;br /&gt;}&lt;/pre&gt;Eliminating the variables altogether will increase the maintainability index to 76.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public static String Sha1(String text)&lt;br /&gt;{&lt;br /&gt;    using (SHA1Managed sha1 = new SHA1Managed())&lt;br /&gt;    {&lt;br /&gt;        return&lt;br /&gt;            Convert.ToBase64String(sha1.ComputeHash(&lt;br /&gt;                Encoding.Unicode.GetBytes(text)));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;76 is better than 71, but is the latter code really more readable and maintainable?&lt;br /&gt;&lt;br /&gt;I posted this example to &lt;a href="http://stackoverflow.com/questions/2749082/why-does-this-maintainability-index-increase"&gt;StackOverflow&lt;/a&gt; and asked if anyone knew why the metric would even increase in the first place. The responders agreed it is counter-intuitive, and the consensus is that it is better to focus on writing clean, concise, readable code.&lt;br /&gt;&lt;br /&gt;An extremely low-scoring metric can be an indicator that something should be flagged for review, but use your discretion and judgment when reviewing the code. Use the report &lt;em&gt;as a tool&lt;/em&gt; to identify possible problems and not a set of requirements to be met.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-434246070166465327?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/434246070166465327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/05/use-discretion-when-reviewing-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/434246070166465327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/434246070166465327'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/05/use-discretion-when-reviewing-code.html' title='Use Discretion when Reviewing Code Metrics'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-4619455751637725730</id><published>2010-04-24T00:05:00.002-04:00</published><updated>2010-04-24T00:07:03.774-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#/.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Signing Assemblies with a Strong Name</title><content type='html'>Code Analysis/FXCop warned me that my &lt;a href="http://zaemis.blogspot.com/2010/04/code-analysis-in-visual-studio.html"&gt;credit card application&lt;/a&gt; was not signed with a Strong Name, which would make it more difficult to determine if the assemblies had been tampered with. For more information on Strong Names and why they're a good thing, see this &lt;a href="http://articles.techrepublic.com.com/5100-10878_11-5054496.html"&gt;Tech Republic article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;you first need a cryptographic key before you can sign an assembly. The key is created using the &lt;a href="http://msdn.microsoft.com/en-us/library/k5b5tt23%28VS.80%29.aspx"&gt;sn.exe tool&lt;/a&gt; provided by the &lt;a href="http://msdn.microsoft.com/en-us/windows/bb980924.aspx"&gt;Windows SDK&lt;/a&gt;.&lt;br /&gt;&lt;pre&gt;sn.exe -k sgKey.snk&lt;br /&gt;&lt;/pre&gt;I added my sgKey.snk file to my project in Visual Studio, and then in the Application's properties I went to the Signing tab, checked the "Sign the assembly" box, and specified my key file.&lt;br /&gt;&lt;br /&gt;I had forgotten that I used a 3rd party library to manage logging the user out after a configurable period of inactivity and their assembly was not signed. You can't sign an assembly unless all of its dependencies are signed as well, which makes sense. You need to replace the unsigned assemblies with signed ones first.&lt;br /&gt;If you can compile the 3rd party library from source, you can sign it yourself; otherwise you'll want to ask them to provide you with a signed assembly. I was in an odd situation where I had compiled the library but had not saved the code, and couldn't find the open source project from which I originally gotten the code. My solution was to sign it myself by disassembling the assembly, and re-assembling it using my key.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/f7dy01k1%28VS.80%29.aspx"&gt;ildasm.exe tool&lt;/a&gt; is used to disassemble .NET assemblies.&lt;br /&gt;&lt;pre&gt;ildasm /output:Timer.il Timer.dll&lt;br /&gt;&lt;/pre&gt;Then, the &lt;a href="http://msdn.microsoft.com/en-us/library/496e4ekx%28v=VS.80%29.aspx"&gt;ilasm.exe tool&lt;/a&gt; let me provide my key file and re-assemble the library so I had a signed assembly.&lt;br /&gt;&lt;pre&gt;ilasm /dll /key:sgKey.snk  Timer.il&lt;br /&gt;&lt;/pre&gt;ildasm.exe is provided by the Windows SDK, and ilasm can be found in your %WINDIR%\Microsoft.NET\Framework\v## directory (where ## is replaced by an appropriate version number of the .NET Framework).&lt;br /&gt;&lt;br /&gt;It's not uncommon to have multiple versions of .NET installed on a computer, let alone on a developer's computer, so be sure to use ilasm.exe for the lowest version of .NET you wish to support when you re-assemble your library. You can't assemble it with v4.0.30319\ilasm.exe if you're targeting a .NET 2.0 platform.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-4619455751637725730?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/4619455751637725730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/04/signing-assemblies-with-strong-name.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4619455751637725730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4619455751637725730'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/04/signing-assemblies-with-strong-name.html' title='Signing Assemblies with a Strong Name'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-3709499736287165844</id><published>2010-04-22T21:53:00.000-04:00</published><updated>2010-04-23T23:56:01.464-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#/.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Code Analysis in Visual Studio</title><content type='html'>Continuing to &lt;a href="http://zaemis.blogspot.com/2010/04/visual-studio-2010-released.html"&gt;play around with Visual Studio 2010 Ultimate&lt;/a&gt;, I ran the Code Analysis tool on some code I had written for a customer-- a desktop-based application which securely stores credit card information using hardware identifiers as portions of the encryption key. I started with over 300 warnings and have now worked them down to around 120 warnings or so. Those that remain are Globalization related, which I'm not concerned about since it was a one-off project that is unlikely to be internationalized. &lt;a href="http://msdn.microsoft.com/en-us/library/bb429476%28VS.80%29.aspx"&gt;FxCop&lt;/a&gt;, the utility which Code Analysis is based on, is freely &lt;a href="http://go.microsoft.com/fwlink/?LinkId=180978"&gt;available online&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-3709499736287165844?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/3709499736287165844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/04/code-analysis-in-visual-studio.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3709499736287165844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3709499736287165844'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/04/code-analysis-in-visual-studio.html' title='Code Analysis in Visual Studio'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6853531123387327612</id><published>2010-04-20T22:44:00.005-04:00</published><updated>2010-04-23T23:52:31.836-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#/.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Visual Studio 2010 Released</title><content type='html'>If you haven't heard the news already (which I hadn't because I typically don't keep up with such things), Visual Studio 2010 came out earlier this month. I've been playing around with &lt;a href="http://www.microsoft.com/visualstudio/en-us/download"&gt;Visual Studio 2010 Ultimate&lt;/a&gt; (a 90-day trial version is available) and I must say I'm impressed. Microsoft has finally added common features like block editing and text-zoom, an Extension Manager to extend the IDE à la Eclipse, and support for jQuery. If I were a Fortune 500 company hacking out Windows code all day I could justify a couple of licenses if it really helped my developers efficiently produce a more secure and stable application, but the price tag puts it far out of reach for my needs. I'll stick with either VS2005 or C# Express 2010.&lt;br /&gt;&lt;br /&gt;I'll probably post a few follow-up entries as I explore more throughout the next 90 days, so be sure to keep an eye out!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6853531123387327612?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6853531123387327612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/04/visual-studio-2010-released.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6853531123387327612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6853531123387327612'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/04/visual-studio-2010-released.html' title='Visual Studio 2010 Released'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6282730751614883192</id><published>2010-03-29T21:42:00.004-04:00</published><updated>2010-03-29T21:53:26.617-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Null Pointer Exception</title><content type='html'>This is why I don't program in Java:&lt;br /&gt;&lt;pre&gt;import java.util.ArrayList;&lt;br /&gt;&lt;br /&gt;class Program&lt;br /&gt;{&lt;br /&gt;   class Person&lt;br /&gt;   {&lt;br /&gt;       public Person partner;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   class Prostitute extends Person { }&lt;br /&gt;   class Eunich extends Person { }&lt;br /&gt;&lt;br /&gt;   private Prostitute prostitute;&lt;br /&gt;   private Eunich eunich;&lt;br /&gt;&lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;       Program p = new Program();&lt;br /&gt;       p.run();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void run() {&lt;br /&gt;       eunich.partner = prostitute;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&gt; Exception in thread "main" java.lang.NullPointerException&lt;/pre&gt;&lt;br /&gt;But if you do, you should check out the nifty online &lt;a href="http://www.innovation.ch/java/java_compile.html"&gt;JXXX Compiler Service&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6282730751614883192?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6282730751614883192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/03/null-pointer-exception.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6282730751614883192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6282730751614883192'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/03/null-pointer-exception.html' title='Null Pointer Exception'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5693525861355811049</id><published>2010-02-19T20:58:00.005-05:00</published><updated>2011-06-04T18:26:30.978-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Subversion Aversion</title><content type='html'>There once was an app called Subversion&lt;br /&gt;Who's working was utter perversion;&lt;br /&gt;    Whether a check in or check out, I'm always in doubt&lt;br /&gt;If it's preserving my coding excursion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5693525861355811049?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5693525861355811049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/02/subversion-aversion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5693525861355811049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5693525861355811049'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/02/subversion-aversion.html' title='Subversion Aversion'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-7028370207485216263</id><published>2010-02-05T22:26:00.009-05:00</published><updated>2010-02-05T22:43:34.922-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>When Will We Ever Use This?</title><content type='html'>My sister's boyfriend showed me a &lt;a href="http://s3.carltonbale.com/resolution_chart.html"&gt;nifty chart&lt;/a&gt; which presents the size of by distance from a television before your eyes begin to notice the difference of 1080p resolution. Just out of curiosity, we measured the length of my living room and looked at the chart to see how large of a television I would need. The distance between my couch and television is a bit shy of 20ft... off the chart!&lt;br /&gt;&lt;br /&gt;The chart goes up to 130 inches, or approximately 11 feet.  But an 11 ft diagonal measurement doesn't really mean anything to me other than "big ass TV"*, so I decided to dig out my high school math skills to help me put it into perspective. Assuming a standard 16:9 wide screen display and some liberal number rounding:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.saltcitytech.com/blogger/math.png" alt="math" style="border:none !important;" /&gt;&lt;br /&gt;&lt;br /&gt;I would need a television that's almost 6 ft tall, and 10 ft wide if I wanted to see Jay Leno's crow's-feet in high definition!&lt;br /&gt;&lt;br /&gt;I only have 8 ft ceilings so that gives 2 ft of clearance above it, and the room is 16 ft wide so I'd have 3 ft of clearance on each side (just 6 inches wider than the width of my door casings). That's not a "big ass TV"... that's my wall!&lt;br /&gt;&lt;br /&gt;I realized two things after running the numbers: First, that was a great real-life example to answer the question "when will we ever use this stuff?" we were all asking our teachers when we were learning algebra. Secondly, I wonder how many people are wasting money on all the latest and greatest video technology. I'm glad I don't own a Blu-ray player, or I'd now be scratching my head wondering "when will I ever use &lt;i&gt;this&lt;/i&gt; stuff?"&lt;br /&gt;&lt;br /&gt;* For my friends in metric countries, that's "big &lt;i&gt;arse&lt;/i&gt; television"&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-7028370207485216263?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/7028370207485216263/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/02/when-will-we-ever-use-this.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7028370207485216263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/7028370207485216263'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/02/when-will-we-ever-use-this.html' title='When Will We Ever Use This?'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8320989447666590327</id><published>2010-01-04T23:15:00.005-05:00</published><updated>2010-01-04T23:20:42.034-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><title type='text'>Writing a URI Regular Expression</title><content type='html'>A friend of mine was tasked with writing a regular expression that could recognize a Uniform Resource Identifier (URI) and break apart its primary components. Not a terribly difficult task since there are a lot of sample regexs one can just pluck from the Internet. But he asked my opinion and I deferred to &lt;a href="http://tools.ietf.org/html/rfc3986"&gt;RFC 3986&lt;/a&gt; which outlines the generic syntax for URIs.&lt;br /&gt;&lt;br /&gt;The RFC provides &lt;a href="http://tools.ietf.org/html/rfc3986#page-51"&gt;this example expression&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&lt;/pre&gt;Personally though I think that's rather sloppy. Were I to write the expression from scratch myself then I'd probably be more verbose and restrictive; I'd expressly match patterns specified in the &lt;a href="http://tools.ietf.org/html/rfc3986#appendix-A"&gt;RFC's ABNF&lt;/a&gt;. For example, the RFC defines the scheme portion of a URI as:&lt;br /&gt;&lt;pre&gt;scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )&lt;/pre&gt;The portion &lt;tt&gt;^([^:/?#]+):&lt;/tt&gt; will match characters that are not lexically permitted, such as an underscore or percent-sign. Assuming the &lt;tt&gt;i&lt;/tt&gt; (case-insensitive matching) modifier is used, something like &lt;tt&gt;^([A-Z][A-Z\d\+\-\.]*):&lt;/tt&gt; would be more correct.&lt;br /&gt;&lt;br /&gt;This highlights one of the joys of writing regexs; regexs is one of the few areas of computing in which you don't have to be completely accurate to achieve the desired results. A "close-enough" match will suffice most of the time.&lt;br /&gt;&lt;br /&gt;While I'm on the topic of regexs, check out gskinner.com's RegExr: Online Regular Expression Testing Tool at &lt;a href="http://www.gskinner.com/RegExr/"&gt;www.gskinner.com/RegExr/&lt;/a&gt; if you haven't already. It’s a great utility!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8320989447666590327?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8320989447666590327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/01/writing-uri-regular-expression.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8320989447666590327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8320989447666590327'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/01/writing-uri-regular-expression.html' title='Writing a URI Regular Expression'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2281818409621897162</id><published>2010-01-03T01:29:00.008-05:00</published><updated>2010-01-16T12:22:30.378-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Install Notes'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>PHP and SQLite2 on CentOS</title><content type='html'>I'm changing shared hosting providers for my websites and the sites I manage for clients as Salt City Tech. Most of the sites are basic websites powered by PHP, share a common code base, and store data in MySQL databases. But I've also been taking advantage of the situation to transition the sites from MySQL to SQLite. There are a lot of things that annoy me about SQLite (such as &lt;a href="http://www.nntp.perl.org/group/perl.dbi.users/2009/10/msg34336.html"&gt;allowing NULLs in primary-key columns&lt;/a&gt;, &lt;a href="http://www2.sqlite.org/omitted.html"&gt;ignoring foreign key constrains, and incomplete ALTER TABLE support&lt;/a&gt;) and a few things that I think are pretty awesome (such as &lt;a href="http://php.net/sqlite_create_function"&gt;user-defined functions in PHP&lt;/a&gt;). Pragmatically speaking, SQLite will be more convenient for deployment to and backup from the shared hosting environment and the sites' simple storage requirements fall exactly in SQLite's sweet-spot.&lt;br /&gt;&lt;br /&gt;The transition hasn't been terribly difficult... the biggest obstacle has been configuring a development environment that adequately mirrored the shared hosting deployment environment. I happened to have a cloned virtual CentOS 5.3 image at my disposal so I started with that, but the hosting provider supports SQLite v2 (ancient!), which's storage format is incompatible with the newer version 3 in CentOS. The search engines didn't offer me much help in finding a packaged SQLite2 solution on CentOS that would meet my needs, so I figured I'd post a few notes in case someone else may find them helpful.&lt;br /&gt;&lt;br /&gt;Obtain the sqlite-2 RPM for CentOS from RPMForge repository (in case you want to work with the database files directly):&lt;br /&gt;&lt;pre&gt;wget &lt;a href="http://dag.wieers.com/rpm/packages/sqlite/sqlite-2.8.17-1.el5.rf.i386.rpm"&gt;http://dag.wieers.com/rpm/packages/sqlite/&lt;br /&gt;sqlite-2.8.17-1.el5.rf.i386.rpm&lt;/a&gt;&lt;/pre&gt;Install sqlite using the &lt;tt&gt;-i&lt;/tt&gt; and &lt;tt&gt;--force&lt;/tt&gt; options (&lt;strong&gt;do not&lt;/strong&gt; use &lt;tt&gt;-U&lt;/tt&gt; so you do not replace sqlite3):&lt;br /&gt;&lt;pre&gt;rpm -i --force sqlite-2.8.17-1.el5.rf.i386.rpm&lt;/pre&gt;Install the php-devel package so &lt;tt&gt;phpize&lt;/tt&gt; and &lt;tt&gt;phpconfig&lt;/tt&gt; are available:&lt;br /&gt;&lt;pre&gt;yum install php-devel&lt;/pre&gt;Obtain the source RPM for PHP (CentOS installs 5.1.6--yuck! Now I remember why I hate using packages for important software):&lt;br /&gt;&lt;pre&gt;wget &lt;a href="ftp://mirror.switch.ch/pool/3/mirror/centos/5.3/os/SRPMS/php-5.1.6-23.el5.src.rpm"&gt;ftp://mirror.switch.ch/pool/3/mirror/centos/5.3/os/SRPMS/&lt;br /&gt;php-5.1.6-23.el5.src.rpm&lt;/a&gt;&lt;/pre&gt;Extract PHP from the SRPM:&lt;br /&gt;&lt;pre&gt;rpm2cpio php-5.1.6-23.el5.src.rpm | cpio -id php-5.1.6.tar.gz&lt;/pre&gt;Uncompress the archive:&lt;br /&gt;&lt;pre&gt;tar zxvf php-5.1.6.tar.gz&lt;/pre&gt;Build the sqlite extension using the standard &lt;tt&gt;phpize&lt;/tt&gt;, &lt;tt&gt;./configure&lt;/tt&gt;, &lt;tt&gt;make&lt;/tt&gt; routine:&lt;br /&gt;&lt;pre&gt;cd php-5.1.6/ext/sqlite&lt;br /&gt;phpize&lt;br /&gt;./configure&lt;br /&gt;make&lt;/pre&gt;Install the extension:&lt;br /&gt;&lt;pre&gt;cp modules/sqlite.so /usr/lib/php/modules/&lt;br /&gt;echo extension=sqlite.so &gt; /etc/php.d/sqlite2.ini&lt;/pre&gt;Even though it's been obsoleted by version 3 for almost 6 years now, version 2 of SQLite works fine for my needs here. And God forbid I have to migrate the sites again or the provider upgrades, upgrading my code base is as simple as this:&lt;br /&gt;&lt;pre&gt;sqlite site.db.old .dump | sqlite3 site.db&lt;br /&gt;for f in $(ls *php); do&lt;br /&gt;sed -i 's/new SQLiteDatabase/new SQLite3/g' $f&lt;br /&gt;sed -i 's/fetch\(SQLITE_ASSOC\)/fetchArray\(SQLITE3_ASSOC\)/g' $f&lt;br /&gt;done&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2281818409621897162?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2281818409621897162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/01/php-and-sqlite2-on-centos.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2281818409621897162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2281818409621897162'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/01/php-and-sqlite2-on-centos.html' title='PHP and SQLite2 on CentOS'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-4386229887389342056</id><published>2010-01-01T00:26:00.001-05:00</published><updated>2010-01-16T12:26:59.760-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>Happy 2010!</title><content type='html'>Happy New Year! I hope everyone has had a rewarding holiday and will have a prosperous new year! Last year I tentatively designated 2009 as my "Year of Balance." I wanted to make a concerted effort to focus more on what's really important in life. With a busy full-time job, a death in the family, juggling several side-projects, and buying a house this year (2009 was probably my "Year of Expense" in retrospect with the new house and all the joys that come with home ownership)... my head would probably have exploded had I not been making that effort. I'm not sure what my theme for 2010 will be, but I'll still be doing my best live, laugh, and love as much as I can and I hope you will be to!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-4386229887389342056?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/4386229887389342056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2010/01/happy-2010.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4386229887389342056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4386229887389342056'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2010/01/happy-2010.html' title='Happy 2010!'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5430346471773826122</id><published>2009-10-12T20:17:00.012-04:00</published><updated>2010-12-05T14:34:00.591-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Pop Quiz</title><content type='html'>Here's a little test to separate the serious coders from the cut-and-paste script kiddies. Given the need to generate an arbitrarily long string consisting of random alpha-numeric characters, which solution is best?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Solution A:&lt;/b&gt;&lt;pre&gt;function randomString($len) {&lt;br /&gt;    $chars  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" .&lt;br /&gt;              "abcdefghijklmnopqrstuvwxyz" .&lt;br /&gt;              "0123456789";&lt;br /&gt;    $rndMax = strlen($chars) - 1;&lt;br /&gt;    $str = "";&lt;br /&gt;    while ($len-- != 0) {&lt;br /&gt;        $str .= $chars[rand(0, $rndMax)];&lt;br /&gt;    }&lt;br /&gt;    return $str;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$str = randomString(8);&lt;br /&gt;echo "$str\n";&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Solution B:&lt;/b&gt;&lt;pre&gt;class RandomSequenceIterator implements Iterator&lt;br /&gt;{&lt;br /&gt;    protected $seqMembers;&lt;br /&gt;    protected $key;&lt;br /&gt;    protected $limit;&lt;br /&gt;&lt;br /&gt;    public function __construct() {&lt;br /&gt;        $this-&amp;gt;setMembers(null)&lt;br /&gt;             -&amp;gt;setLimit(0)&lt;br /&gt;             -&amp;gt;rewind();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected function setMembers($strValue) {&lt;br /&gt;        $this-&amp;gt;seqMembers = $strValue;&lt;br /&gt;        return $this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected function getMembers() {&lt;br /&gt;        return $this-&amp;gt;seqMembers;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected function setLimit($intValue) {&lt;br /&gt;        $this-&amp;gt;limit = $intValue;&lt;br /&gt;        return $this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected function getLimit() {&lt;br /&gt;        if (empty($this-&amp;gt;limit)) {&lt;br /&gt;            return 0;&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            return $this-&amp;gt;limit;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function current() {&lt;br /&gt;        $index = rand(0, strlen($this-&amp;gt;getMembers()) - 1);&lt;br /&gt;        return substr($this-&amp;gt;getMembers(), $index, 1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function valid() {&lt;br /&gt;        return $this-&amp;gt;key() &amp;lt; $this-&amp;gt;getLimit();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function key() {&lt;br /&gt;        return $this-&amp;gt;key;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function next() {&lt;br /&gt;        $this-&amp;gt;key++;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function reset() {&lt;br /&gt;        $this-&amp;gt;rewind();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function rewind() {&lt;br /&gt;        $this-&amp;gt;key = 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RandomCharacterSequenceGenerator extends&lt;br /&gt;RandomSequenceIterator&lt;br /&gt;{&lt;br /&gt;    public function setChars($strValue) {&lt;br /&gt;        $this-&amp;gt;setMembers($strValue);&lt;br /&gt;        return $this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function getChars() {&lt;br /&gt;        return $this-&amp;gt;getMembers();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function generate($limit) {&lt;br /&gt;        $strBuffer = "";&lt;br /&gt;        $this-&amp;gt;setLimit($limit);&lt;br /&gt;        foreach ($this as $char) {&lt;br /&gt;            $strBuffer .= $char;&lt;br /&gt;        }&lt;br /&gt;        return $strBuffer;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;abstract class RandomGeneratorBase&lt;br /&gt;{&lt;br /&gt;    protected static $instance;&lt;br /&gt;    protected static $generator;&lt;br /&gt;&lt;br /&gt;    protected function __construct() {&lt;br /&gt;        self::$generator = new&lt;br /&gt;            RandomCharacterSequenceGenerator();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // abstract public static function getInstance();&lt;br /&gt;    public static function getInstance() {&lt;br /&gt;        if (empty(self::$instance)) {&lt;br /&gt;            self::$instance = new self();&lt;br /&gt;        }&lt;br /&gt;        return self::$instance;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public function generate($limit) {&lt;br /&gt;        return self::$generator-&amp;gt;generate($limit);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RandomNumericStringGenerator extends RandomGeneratorBase&lt;br /&gt;{&lt;br /&gt;    const VALID_MEMBERS = "0123456789";&lt;br /&gt;&lt;br /&gt;    protected function __construct() {&lt;br /&gt;        parent::__construct();&lt;br /&gt;        self::$generator-&amp;gt;setChars(self::VALID_MEMBERS);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static function getInstance() {&lt;br /&gt;        if (empty(self::$instance)) {&lt;br /&gt;            self::$instance = new self();&lt;br /&gt;        }&lt;br /&gt;        return self::$instance;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RandomUpperCaseAlphaStringGenerator extends&lt;br /&gt;RandomGeneratorBase&lt;br /&gt;{&lt;br /&gt;    const VALID_MEMBERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";&lt;br /&gt;&lt;br /&gt;    protected function __construct() {&lt;br /&gt;        parent::__construct();&lt;br /&gt;        self::$generator-&amp;gt;setChars(self::VALID_MEMBERS);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static function getInstance() {&lt;br /&gt;        if (empty(self::$instance)) {&lt;br /&gt;            self::$instance = new self();&lt;br /&gt;        }&lt;br /&gt;        return self::$instance;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RandomLowerCaseAlphaStringGenerator extends&lt;br /&gt;RandomGeneratorBase&lt;br /&gt;{&lt;br /&gt;    const VALID_MEMBERS = "abcdefghijklmnopqrstuvwxyz";&lt;br /&gt;&lt;br /&gt;    protected function __construct() {&lt;br /&gt;        parent::__construct();&lt;br /&gt;        self::$generator-&amp;gt;setChars(self::VALID_MEMBERS);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static function getInstance() {&lt;br /&gt;        if (empty(self::$instance)) {&lt;br /&gt;            self::$instance = new self();&lt;br /&gt;        }&lt;br /&gt;        return self::$instance;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RandomMixedCaseAlphaStringGenerator extends&lt;br /&gt;RandomGeneratorBase&lt;br /&gt;{&lt;br /&gt;    protected function __construct() {&lt;br /&gt;        parent::__construct();&lt;br /&gt;        self::$generator-&amp;gt;setChars(&lt;br /&gt;           RandomUpperCaseAlphaStringGenerator::VALID_MEMBERS .&lt;br /&gt;           RandomLowerCaseAlphaStringGenerator::VALID_MEMBERS);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static function getInstance() {&lt;br /&gt;        if (empty(self::$instance)) {&lt;br /&gt;            self::$instance = new self();&lt;br /&gt;        }&lt;br /&gt;        return self::$instance;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RandomMixedCaseAlphaNumericStringGenerator extends&lt;br /&gt;RandomMixedCaseAlphaStringGenerator&lt;br /&gt;{&lt;br /&gt;    protected function __construct() {&lt;br /&gt;        parent::__construct();&lt;br /&gt;        self::$generator-&amp;gt;setChars(&lt;br /&gt;            RandomNumericStringGenerator::VALID_MEMBERS .&lt;br /&gt;            self::$generator-&amp;gt;getChars());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static function getInstance() {&lt;br /&gt;        if (empty(self::$instance)) {&lt;br /&gt;            self::$instance = new self();&lt;br /&gt;        }&lt;br /&gt;        return self::$instance;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$str = RandomMixedCaseAlphaNumericStringGenerator&lt;br /&gt;       ::getInstance()&lt;br /&gt;       -&amp;gt;generate(8);&lt;br /&gt;echo "$str\n";&lt;br /&gt;&lt;/pre&gt;If you managed to scroll down this far, congratulations! You are a true programmer who knows the correct answer is &lt;strong&gt;B&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Solution A is a good example of unorganized spaghetti-code. It "works" but it's amateurish. A uses only language-primitives-- none of the advanced, enterprise architecture concepts embodied in Solution B. It is certainly not flexible. (What if one changed the requirements to generate a random string of only digits, for example?)&lt;br /&gt;&lt;br /&gt;Solution B is much more organized, encapsulated, and extensible. Object-oriented code models the way things are in the "real world" so it's easier to conceptualize what the code is doing. The problem is broken down into several smaller, more manageable ones, and uses interfaces, abstract classes, and inheritance to eliminate redundant code, facilitate better organization, and foster code-reuse. Understanding existing code is an important part of programming and the liberal use of design patterns such as Singleton and Decorator embody solutions to common problems giving programmers a common vocabulary with higher levels of abstraction to communicate with one another.&lt;br /&gt;&lt;br /&gt;Of course, solution B should only serve as an example and not be used as-is in a production environment. Exceptions should be used, but are omitted here for the sake of brevity. And the actual invocation to generate the random string could probably be further encapsulated and abstracted by implementing the Factory design pattern and maybe the Registry pattern-- one would query the registry for a value object to pass to the factory, and in turn the factory would determine which type of generator to return: random uppercase alpha, random numeric, mixed case, etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5430346471773826122?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5430346471773826122/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/10/pop-quiz.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5430346471773826122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5430346471773826122'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/10/pop-quiz.html' title='Pop Quiz'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-4848557525111169976</id><published>2009-10-07T01:18:00.008-04:00</published><updated>2010-01-03T01:48:41.628-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Install Notes'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Setting Up SFTP From PHP</title><content type='html'>PHP's &lt;a href="http://www.php.net/ftp-ssl-connect"&gt;ftp_ssl_connect()&lt;/a&gt; function is for SSL-FTP, where as what I need for a client's application is SFTP. Isn't life grand! Well, it's not really too much trouble... PHP can handle that too with functions from the ssh2 PECL extension. I'm just glad I caught it early on instead of at the 11th hour. I figured though I might as well continue &lt;a href="http://zaemis.blogspot.com/2009/09/creating-centos-based-lamp-virtual.html"&gt;my previous post&lt;/a&gt; about setting up this project with a brief description on installing ssh2 and testing it to ensure everything is in working order.&lt;br /&gt;&lt;h4&gt;Installation&lt;/h4&gt;The ssh2 extension provides bindings to &lt;a href="http://www.blogger.com/%20http://www.sourceforge.net/projects/libssh2"&gt;libssh2&lt;/a&gt; which must be installed first on the system. My target platform is CentOS 5.3, so I was able to install libssh2 and libssh2-devel via &lt;tt&gt;yum&lt;/tt&gt; (using the &lt;a href="http://www.blogger.com/%20http://rpmrepo.org/RPMforge"&gt;RPMForge&lt;/a&gt; repository).&lt;br /&gt;&lt;pre&gt;yum install libssh2 libssh2-devel&lt;/pre&gt;The ssh2 extension is available from the &lt;a href="http://www.blogger.com/%20http://pecl.php.net/package/ssh2"&gt;pecl.php.net website&lt;/a&gt;. There is a minor bug in the current version (0.11.0) which prevents it from compiling against PHP 5.3 so I needed to apply &lt;a href="http://remi.fedorapeople.org/ssh2-php53.patch"&gt;this patch&lt;/a&gt;.&lt;br /&gt;&lt;pre&gt;wget http://remi.fedorapeople.org/ssh2-php53.patch&lt;br /&gt;tar zxf ssh2-0.11.0.tgz&lt;br /&gt;cd ssh2-0.11.0&lt;br /&gt;patch &amp;lt; ../ssh2-php53.patch&lt;/pre&gt;I compiled and installed the extension after the code was patched.&lt;br /&gt;&lt;pre&gt;phpize&lt;br /&gt;./configure --with-ssh2&lt;br /&gt;make&lt;br /&gt;cp modules/ssh2.so /usr/local/php/lib/php/extensions/&lt;/pre&gt;Adding &lt;tt&gt;module=ssh2.so&lt;/tt&gt; to &lt;tt&gt;php.ini&lt;/tt&gt; and restarting Apache completed the installation. I was then ready to move on and test it to make sure it worked as it should.&lt;br /&gt;&lt;h4&gt;Testing the Extension&lt;/h4&gt;Using the extension to upload and retrieve files programmatically over an SFTP connection is relatively simple. First, a secure shell connection is established with the SFTP server using &lt;a href="http://www.php.net/ssh2_connect"&gt;ssh2_connect()&lt;/a&gt;, and then a login is authenticated with &lt;a href="http://www.php.net/ssh2_auth_password"&gt;ssh2_auth_password()&lt;/a&gt;. Both functions return false if they fail:&lt;br /&gt;&lt;pre&gt;$sess = @ssh2_connect(SFTP_SERVER, SFTP_PORT);&lt;br /&gt;if ($sess === false) {&lt;br /&gt;   echo "Connection failed.";&lt;br /&gt;   exit(-1);&lt;br /&gt;}&lt;br /&gt;$result = @ssh2_auth_password($sess, SFTP_USERNAME,&lt;br /&gt;   SFTP_PASSWORD);&lt;br /&gt;if ($result === false) {&lt;br /&gt;   echo "Unable to authenticate.";&lt;br /&gt;   exit(-1);&lt;br /&gt;}&lt;/pre&gt;Once a session has been established, the &lt;a href="http://www.php.net/ssh2_sftp"&gt;ssh2_sftp()&lt;/a&gt; function is used to retrieve an SFTP resource.&lt;br /&gt;&lt;pre&gt;$sftp = @ssh2_sftp($sess);&lt;br /&gt;if ($sftp === false) {&lt;br /&gt;   echo "Unable to initialize SFTP subsystem.";&lt;br /&gt;   exit(-1);&lt;br /&gt;}&lt;/pre&gt;From that point on, the SFTP resource is used with the &lt;tt&gt;ssh2.sftp&lt;/tt&gt; filestream to read and write files.&lt;br /&gt;&lt;pre&gt;file_put_contents("ssh2.sftp://" . $sftp . "/tmp/test.txt",&lt;br /&gt;   $data);&lt;/pre&gt;In writing my short automated test case, I dumped some bytes from &lt;tt&gt;/dev/urandom&lt;/tt&gt; to generate a test file, wrote the data to the SFTP server, read it back, and compared the results to make sure they matched after the round-trip.&lt;br /&gt;&lt;pre&gt;// generate random data for test file&lt;br /&gt;$data = file_get_contents("/dev/urandom", FILE_BINARY, null,&lt;br /&gt;   0, 512);&lt;br /&gt;$data = substr(convert_uuencode($data), 0, 512);&lt;br /&gt;&lt;br /&gt;// write data to file on SFTP server&lt;br /&gt;file_put_contents("ssh2.sftp://" . $sftp . "/tmp/test.txt",&lt;br /&gt;   $data);&lt;br /&gt;&lt;br /&gt;// retrieve file from SFTP server&lt;br /&gt;$retrieved = file_get_contents("ssh2.sftp://" . $sftp .&lt;br /&gt;   "/tmp/test.txt");&lt;br /&gt;&lt;br /&gt;// compare original data with retrieve data&lt;br /&gt;echo ($data == $retrieved) ? "Success!" : "Corruption!";&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-4848557525111169976?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/4848557525111169976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/10/setting-up-sftp-from-php.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4848557525111169976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4848557525111169976'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/10/setting-up-sftp-from-php.html' title='Setting Up SFTP From PHP'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6582842247392172572</id><published>2009-09-26T21:30:00.008-04:00</published><updated>2010-01-03T01:48:41.629-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Install Notes'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Virtualization'/><title type='text'>Creating a CentOS-Based LAMP Virtual Image</title><content type='html'>In doing some preliminary research and planning for a client's new project, I determined his current in-house deployment platform would not be sufficient given his requirements. Specifically, the project calls for a moderate amount of URL re-writing and the ability to programmatically FTP files to a remote host. The client is running IIS on Windows Server 2008; I’m not too keen on &lt;a href="http://www.isapirewrite.com/"&gt;ISAPI rewrite&lt;/a&gt; and IIS Rewrite seems to have fallen off the face of the Internet, and the &lt;a href="http://www.php.net/ftp_ssl_connect"&gt;ftp_ssl_connect()&lt;/a&gt; function is only available in PHP if both the ftp module and OpenSSL support are statically built-in so we would have to maintain a build environment for him, too. A LAMP-stack makes more sense. Apache can rewrite URLs with mod_rewrite and compiling PHP is a more supported practice on Linux than it is on Windows.&lt;br /&gt;&lt;br /&gt;I discussed the obstacles and some possible solutions with the client and he's okay with LAMP. Instead of bringing in more hardware, though, I suggested taking advantage of virtualization. I assured him I could create a virtual platform that would provide us with everything we need, appear as a new machine on his network, and run directly on top of Windows Server 2008.&lt;h4&gt;Installing CentOS&lt;/h4&gt;Originally I wanted to use the new &lt;a href="http://slackware.com/announce/13.0.php"&gt;Slackware64&lt;/a&gt;, but VMware-Tools proved too much of a struggle to install and I didn't feel comfortable using it for a client's project because of that. I eventually settled on &lt;a href="http://www.wiley.com/WileyCDA/WileyTitle/productCd-047048165X.html"&gt;CentOS 5.3&lt;/a&gt; instead.&lt;br /&gt;&lt;br /&gt;I fired up the trial version of &lt;a href="http://www.vmware.com/products/workstation/index.html"&gt;VMWare Workstation&lt;/a&gt; to configure a basic machine image... though I have VMware Workstation 6.5, I chose to set the virtual machine's hardware compatibility for Workstation 5 and compatible with ESX Server. I figured this will give us some flexibility if we need to move the image to bare-metal in the future. CentOS is built from RHEL sources, so I was able to set the Guest Operating System as Red Hat Enterprise Linux 5 and use any Red Hat-specific documentation VMware has.&lt;br /&gt;&lt;br /&gt;I tried to keep the installation small, so I unchecked everything in Anaconda-- including the Base packages. I still got packages what I feel are unnecessary dependencies (&lt;a href="http://markmail.org/message/wlra2rvlylxfvhjg"&gt;Requiring &lt;tt&gt;wireless-tools&lt;/tt&gt; on a sever installation&lt;/a&gt;, for example. Seriously, Red Hat!), but I guess I can live with it and it won't matter much to the client.&lt;br /&gt;&lt;br /&gt;Once CentOS was installed and booted and I was logged in, I needed to install some packages (and their dependencies) with &lt;tt&gt;yum&lt;/tt&gt; that I didn't install during the installation:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;tt&gt;autoconf&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;curl-devel&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;freetype-devel&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;gcc&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;gcc-c++&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;libjpeg-devel&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;libpng-devel&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;libxml2-devel&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;lynx&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;make&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;ncurses-devel&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;ntp&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;openssl-devel&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;patch&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;perl&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;sendmail&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;wget&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;which&lt;/tt&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;zlib-devel&lt;/tt&gt;&lt;/li&gt;&lt;/ul&gt;Notice I didn't install Apache, MySQL, or PHP. That's because I like to compile and install the major software from source. This way I can make sure they're up to date and configure their builds exactly how I need them.&lt;h4&gt;Configuring Mapped Directories&lt;/h4&gt;I want to keep the application's data separate from the virtual image so I wouldn't be constrained by the size of the image (trying to explain why he couldn't save more than a gig of data when it was running on a physical server with 100 gigs of free drive space wouldn't be fun). The next task was to create shared data directories on the host and install VMware-Tools so I could map them. I created a directory shared as &lt;tt&gt;apache&lt;/tt&gt; to hold the bulk of the application's code (&lt;tt&gt;.php&lt;/tt&gt;, &lt;tt&gt;.html&lt;/tt&gt;, etc), and &lt;tt&gt;mysql&lt;/tt&gt; to hold the database's tables.&lt;br /&gt;&lt;br /&gt;The VMware documentation describes the VMware-Tools installation process in detail, but it's no more difficult than selecting "VM" -&gt; "Install VMware tools..." in VMware Workstation, and then proceeding to install the VMware-Tools RPM in CentOS.&lt;br /&gt;&lt;pre&gt;mount /dev/cdrom /media&lt;br /&gt;rpm -Uvh /media/ VMwareTools-7.8.5-156735.i386.rpm&lt;br /&gt;umount /media&lt;br /&gt;vmware-config-tools.pl&lt;/pre&gt;VMware adds the following to &lt;tt&gt;/etc/fstab&lt;/tt&gt;:&lt;br /&gt;&lt;pre&gt;# Beginning of the block added by the VMware software&lt;br /&gt;.host:/         /mnt/hgfs     vmhgfs   defaults,ttl=5   0 0&lt;br /&gt;# End of the block added by the VMware software&lt;/pre&gt;That entry will make the shared folders on from the host operating system accessible as &lt;tt&gt;/mnt/hgfs/apache&lt;/tt&gt; and &lt;tt&gt;/mnt/hgfs/mysql&lt;/tt&gt;. Everything within them owned by root with global read, write, and execute permissions.  There's not much that can be done about the lax permissions, but I could at least have the files owned by a more appropriate user than root. I wanted to have them each mounted under &lt;tt&gt;/srv&lt;/tt&gt; instead of &lt;tt&gt;/mnt/hgfs&lt;/tt&gt; as well to be a little more LSB compliant (suck it, &lt;tt&gt;/var/www&lt;/tt&gt;!), so I replaced their entry with my own:&lt;br /&gt;&lt;pre&gt;.host:/apache   /srv/apache   vmhgfs   defaults,ttl=5,uid=99,gid=99   0 0&lt;br /&gt;.host:/mysql    /srv/mysql    vmhgfs   defaults,ttl=5,uid=27,gid=27   0 0&lt;/pre&gt;It would be nice if future version of VMware will have a more flexible HGFS driver-- but this will be sufficient for the task at hand. At last I could install Apache, MySQL, and PHP.&lt;h4&gt;Compiling&lt;/h4&gt;There isn't anything too exciting about installing Apache, MySQL, and PHP from source to talk about, so I'll just share with you my configure options.&lt;h5&gt;MySql Enterprise 5.0.88sp2&lt;/h5&gt;&lt;pre&gt;./configure \&lt;br /&gt;--prefix=/usr/local/mysql \&lt;br /&gt;--localstatedir=/srv/mysql \&lt;br /&gt;--with-unix-socket-path=/tmp/mysql.sock \&lt;br /&gt;--with-mysqld-user=mysql \&lt;br /&gt;--without-debug \&lt;br /&gt;--with-archive-storage-engine \&lt;br /&gt;--with-csv-storage-engine \&lt;br /&gt;--with-federated-storage-engine \&lt;br /&gt;--disable-maintainer-mode \&lt;br /&gt;--enable-assembler \&lt;br /&gt;--enable-largefile \&lt;br /&gt;--enable-local-infile \&lt;br /&gt;--enable-thread-safe-client&lt;/pre&gt;&lt;h5&gt;Apache 2.2.13&lt;/h5&gt;&lt;pre&gt;CFLAGS=-O3 ./configure \&lt;br /&gt;--prefix=/usr/local/apache \&lt;br /&gt;--with-pcre \&lt;br /&gt;--disable-status \&lt;br /&gt;--enable-mods-shared=all \&lt;br /&gt;--enable-so \&lt;br /&gt;--enable-ssl \&lt;br /&gt;--enable-setenvif \&lt;br /&gt;--enable-rewrite&lt;/pre&gt;&lt;h5&gt;PHP 5.0.3&lt;/h5&gt;&lt;pre&gt;CFLAGS=-O3 ./configure \&lt;br /&gt;--prefix=/usr/local/php \&lt;br /&gt;--with-apxs2=/usr/local/apache/bin/apxs \&lt;br /&gt;--with-mysql=/usr/local/mysql \&lt;br /&gt;--with-pdo-mysql=/usr/local/mysql \&lt;br /&gt;--with-mysqli=/usr/local/mysql/bin/mysql_config \&lt;br /&gt;--with-gd \&lt;br /&gt;--with-jpeg-dir=/usr/lib \&lt;br /&gt;--with-freetype-dir \&lt;br /&gt;--with-curl \&lt;br /&gt;--with-openssl \&lt;br /&gt;--enable-ftp \&lt;br /&gt;--with-openssl-dir&lt;/pre&gt;After that I needed to open CentOS's firewall to allow HTTPS traffic using &lt;tt&gt;system-config-securitylevel-tui&lt;/tt&gt;, and change the security context of the &lt;tt&gt;libphp5.so&lt;/tt&gt; module for Apache because SELinux is enabled.&lt;h4&gt;Final Housekeeping&lt;/h4&gt;There were only a few minor housekeeping things to attend to after I had everything installed. I had to add a couple kernel parameters and configure &lt;tt&gt;ntp&lt;/tt&gt; according to VMware's &lt;a href="http://kb.vmware.com/selfservice/microsites/search.do?cmd=displayKC&amp;amp;docType=kc&amp;amp;externalId=1006427%22"&gt;Time Keeping Best Practices for Linux&lt;/a&gt; so the time didn't drift. It was also important that I configure &lt;tt&gt;logrotate&lt;/tt&gt; to rotate Apache and MySQL's log files as I did not install them via RPM. Otherwise they could grow unwieldy and use up all the space I had allocated for the virtual image.&lt;br /&gt;&lt;br /&gt;So in short order I had not only a sane platform for deployment, but one I could easily clone and use for development as well. The client only needs the free &lt;a href="http://www.vmware.com/products/player/"&gt;VMware Player&lt;/a&gt; software to use the image. The data directories are on the host operating system alongside the image so they are not constrained by the size of the image and can be backed-up independently of the image. When necessary, upgrading the virtual platform can be done independently of the data.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update 10/04/2009:&lt;/span&gt; It appears the above procedure didn't install a cron daemon, though it did install crontab files-- now isn't that interesting!&lt;br /&gt;&lt;pre&gt;rpm -qa | grep cron&lt;br /&gt;crontabs-1.10-8&lt;/pre&gt;&lt;tt&gt;yum install vixie-cron&lt;/tt&gt; resolved the issue. Don't forget to issue &lt;tt&gt;chkconfig crond on&lt;/tt&gt; so it starts automatically, and &lt;tt&gt;/etc/init.d/crond start&lt;/tt&gt; to start cron for the current session (so you don't have to reboot).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6582842247392172572?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6582842247392172572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/09/creating-centos-based-lamp-virtual.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6582842247392172572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6582842247392172572'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/09/creating-centos-based-lamp-virtual.html' title='Creating a CentOS-Based LAMP Virtual Image'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-4162755970186852863</id><published>2009-07-28T23:11:00.005-04:00</published><updated>2010-01-17T18:57:17.393-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='Paste Ninja'/><title type='text'>New Feature at Paste Ninja</title><content type='html'>Some of you may have noticed last week a new feature was rolled out on &lt;a href="http://pasteninja.com"&gt;Paste Ninja&lt;/a&gt;, the premier PHP-powered paste bin-- patches! Here's how it works:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Update an existing paste&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Click the Compare link that appears in the updated paste's header&lt;/li&gt;&lt;br /&gt;&lt;li&gt;In the Compare dialog that opens, select your desired current and target revisions; a colorized unified diff is displayed so you can verify the changes&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Click the dialog's Download button&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;It’s that simple!&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.saltcitytech.com/blogger/pasteninja.com-diff.jpg"/&gt;&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-4162755970186852863?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/4162755970186852863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/07/new-feature-at-paste-ninja.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4162755970186852863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/4162755970186852863'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/07/new-feature-at-paste-ninja.html' title='New Feature at Paste Ninja'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-362891269854770914</id><published>2009-07-21T01:09:00.014-04:00</published><updated>2011-03-21T00:23:00.168-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><title type='text'>Seamless Error Highlighting</title><content type='html'>A lot of output can be generated when you compiling large projects. When it breaks, it can be difficult to identify the particular spot in the build-process where things when wrong. Highlighting the error messages can help them stand out from the rest of the output.&lt;br /&gt;&lt;br /&gt;ANSI escape sequences can be used to modify how your terminal window displays its text. For example, outputting the sequence &lt;code&gt;&lt;nobr&gt;\033[41;37mHello World\033[0m&lt;/nobr&gt;&lt;/code&gt; would result in "Hello World" displayed in white text against a red background. Escape sequences begin with an escape character (ASCII 27, octal 033) and bracket. The control values are then given (multiple values are semicolon-separated) and the entire sequence closes with &lt;code&gt;m&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;You can highlight certain messages by routing the STDOUT and STDERR streams to sed and performing a replacement.&lt;br /&gt;&lt;pre&gt;s,(.*error.*|.*fail.*|.*undef.*),\033[41;37m\1\033[0m,gi&lt;br /&gt;&lt;/pre&gt;The values you match are of course entirely up to your discretion.&lt;br /&gt;&lt;br /&gt;The tricky part is quoting and escaping the expression correctly so various meta-characters aren't intercepted by the shell. And some implementations of sed won't correctly convert &lt;code&gt;\033&lt;/code&gt; to an escape character, so you may need to enter it directly by typing &lt;code&gt;&lt;i&gt;CTRL+V&lt;/i&gt;&lt;/code&gt;, &lt;code&gt;&lt;i&gt;CTRL+[&lt;/i&gt;&lt;/code&gt;. Depending on your terminal, an actual escape character may be displayed as &lt;code&gt;^[&lt;/code&gt; or a special glyph like &lt;img style="padding:0;border:none;" src="http://saltcitytech.com/blogger/esc.gif" alt="ESC"/&gt; when you enter it.&lt;br /&gt;&lt;pre&gt;make install 2&amp;gt;&amp;amp;1 | sed -e \&lt;br /&gt;'s,\(.*error.*\|.*fail.*\|.*undef.*\),&lt;img style="padding:0;border:none;" src="http://saltcitytech.com/blogger/esc.gif" alt="ESC"/&gt;[41;37m\1&lt;img style="padding:0;border:none;" src="http://saltcitytech.com/blogger/esc.gif" alt="ESC"/&gt;[0m,gi'&lt;br /&gt;&lt;/pre&gt;If you find yourself using such highlighting often, you may want to define a function to save yourself some typing. For example, with bash you can add something like this to your &lt;tt&gt;.bashrc&lt;/tt&gt; file:&lt;br /&gt;&lt;pre&gt;function make() {&lt;br /&gt;/usr/bin/make $@ 2&amp;gt;&amp;amp;1 | sed -e \&lt;br /&gt;'s,\(.*error.*\|.*fail.*\|.*undef.*\),&lt;img style="padding:0;border:none;" src="http://saltcitytech.com/blogger/esc.gif" alt="ESC"/&gt;[41;37m\1&lt;img style="padding:0;border:none;" src="http://saltcitytech.com/blogger/esc.gif" alt="ESC"/&gt;[0m,gi';&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;You can type &lt;code&gt;make install&lt;/code&gt; at the prompt like you normally would. bash will call the new &lt;code&gt;make()&lt;/code&gt; function, which in turn calls the actual make utility with any arguments (such as &lt;code&gt;install&lt;/code&gt;) and colorizes the output. Error highlighting is now seamless and automatic!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-362891269854770914?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/362891269854770914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/07/seamless-error-highlighting.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/362891269854770914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/362891269854770914'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/07/seamless-error-highlighting.html' title='Seamless Error Highlighting'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-3071308586163274247</id><published>2009-07-14T20:12:00.008-04:00</published><updated>2010-01-17T19:10:22.433-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>OOP in JS</title><content type='html'>When people would ask me about Object Oriented Programming in JavaScript, I would always send them to two pages written by Gavin Kistner. The other day when I went to visit them myself to quickly check something, they were gone! What happened, Gavin?!&lt;br /&gt;&lt;br /&gt;I promptly dug the pages up from a search engine's cache to mirror them, but all the original copyrights still belong to Gavin.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://saltcitytech.com/blogger/OOPinJS.html"&gt;OOP in JS, Part1: Public/Private Variables and Methods&lt;/a&gt;&lt;br/&gt;&lt;small&gt;originally at http://phrogz.net/JS/Classes/OOPinJS.html&lt;/small&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://saltcitytech.com/blogger/OOPinJS2.html"&gt;OOP in JS, Part 2:  Inheritance&lt;/a&gt;&lt;br/&gt;&lt;small&gt;originally at http://phrogz.net/JS/Classes/OOPinJS2.html&lt;/small&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-3071308586163274247?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/3071308586163274247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/07/oop-in-js.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3071308586163274247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3071308586163274247'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/07/oop-in-js.html' title='OOP in JS'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6929898231772447310</id><published>2009-06-28T23:48:00.026-04:00</published><updated>2009-06-29T16:00:23.977-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='OCaml/F#'/><title type='text'>Currying in PHP</title><content type='html'>What happens if you don't have all the arguments handy for a function, but you want to give whatever arguments you do have now and then provide the rest of them to the function later? This is called &lt;a href="http://en.wikipedia.org/wiki/Currying"&gt;currying&lt;/a&gt;, and is a core concept in functional programming. It's messy, but possible to curry functions in PHP now that &lt;a href="http://zaemis.blogspot.com/2009/03/anonymous-functions-and-closures.html"&gt;closures have been added&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;First, let me show you how currying looks in a functional language. Here's a basic example in OCaml/F#:&lt;br /&gt;&lt;pre&gt;let do_math op x y =&lt;br /&gt;  match op with&lt;br /&gt;      '+' -&gt; x + y&lt;br /&gt;    | '-' -&gt; x – y&lt;br /&gt;    | _   -&gt; failwith "Invalid op"&lt;br /&gt;&lt;br /&gt;let add = do_math '+'&lt;br /&gt;&lt;br /&gt;let inc = add 1&lt;br /&gt;let dec = add (-1)&lt;br /&gt;;;&lt;br /&gt;&lt;/pre&gt;A function named &lt;tt&gt;do_math&lt;/tt&gt; is defined that accepts an operator and two operands. The function's return value will be either the sum or difference of the operands, depending on whether the given operator is &lt;tt&gt;+&lt;/tt&gt; or &lt;tt&gt;-&lt;/tt&gt;. Notice how &lt;tt&gt;do_math&lt;/tt&gt; is then called with a single argument. OCaml doesn't raise an error; it simply returns a function that "remembers" the first argument and accepts the remaining two arguments later (this is an over-simplified and slightly inaccurate statement, but a good enough description for our purpose here). This intermediate function can be used elsewhere, as in the bindings for &lt;tt&gt;inc&lt;/tt&gt; and &lt;tt&gt;dec&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Now here's a version of the &lt;tt&gt;do_math()&lt;/tt&gt; function in PHP:&lt;br /&gt;&lt;pre&gt;function do_math($op, $x, $y) {&lt;br /&gt;    switch ($op) {&lt;br /&gt;        case '+':&lt;br /&gt;            return $x + $y;&lt;br /&gt;&lt;br /&gt;        case '-':&lt;br /&gt;            return $x - $y;&lt;br /&gt;&lt;br /&gt;        default:&lt;br /&gt;             throw new Exception("Invalid op");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Unfortunately, PHP will throw warnings if you call &lt;tt&gt;do_math()&lt;/tt&gt; without the three arguments it expects.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;&lt;b&gt;Warning:&lt;/b&gt;  Missing argument 2 for do_math(), called in /home/tboronczyk/curry.php on line 16 and defined in &lt;b&gt;/home/tboronczyk/curry.php&lt;/b&gt; on line &lt;b&gt;2&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Warning:&lt;/b&gt;  Missing argument 3 for do_math(), called in /home/tboronczyk/curry.php on line 16 and defined in &lt;b&gt;/home/tboronczyk/curry.php&lt;/b&gt; on line &lt;b&gt;2&lt;/b&gt;&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;Whereas functional languages have currying "built-in," you must explicitly code this ability in an imperative language. Doing so in PHP requires the use of closures:&lt;br /&gt;&lt;pre&gt;function do_math($op) {&lt;br /&gt;    return function ($x) use ($op) {&lt;br /&gt;        return function ($y) use ($op, $x) {&lt;br /&gt;            switch ($op) {&lt;br /&gt;                case "+":&lt;br /&gt;                    return $x + $y;&lt;br /&gt;&lt;br /&gt;                case "-":&lt;br /&gt;                    return $x - $y;&lt;br /&gt;&lt;br /&gt;                default:&lt;br /&gt;                    throw new Exception("Invalid op");&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;    };&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;It's also possible to extend the function using &lt;tt&gt;func_num_args()&lt;/tt&gt; and &lt;tt&gt;func_get_arg()&lt;/tt&gt; functions, anonymous functions, and closures, so that any number of parameters can be given at a time.&lt;br /&gt;&lt;pre&gt;function do_math() {&lt;br /&gt;    if (func_num_args() &gt;= 1) $op = func_get_arg(0);&lt;br /&gt;    if (func_num_args() &gt;= 2) $x  = func_get_arg(1);&lt;br /&gt;    if (func_num_args() == 3) $y  = func_get_arg(2);&lt;br /&gt;&lt;br /&gt;    switch (func_num_args()) {&lt;br /&gt;        case 1:&lt;br /&gt;            return function () use ($op) {&lt;br /&gt;                if (func_num_args() &gt;= 1) $x = func_get_arg(0);&lt;br /&gt;                if (func_num_args() == 2) $y = func_get_arg(1);&lt;br /&gt;&lt;br /&gt;                switch (func_num_args()) {&lt;br /&gt;                    case 1:&lt;br /&gt;                        return function ($y) use ($op, $x) {&lt;br /&gt;                            return do_math($op, $x, $y);&lt;br /&gt;                        };&lt;br /&gt;&lt;br /&gt;                    case 2:&lt;br /&gt;                        return do_math($op, $x, $y);&lt;br /&gt;&lt;br /&gt;                    default:&lt;br /&gt;                        trigger_error(&lt;br /&gt;                            "invalid argument count",&lt;br /&gt;                            E_USER_WARNING);&lt;br /&gt;                }&lt;br /&gt;            };&lt;br /&gt;&lt;br /&gt;        case 2:&lt;br /&gt;            return function ($y) use ($op, $x) {&lt;br /&gt;                return do_math($op, $x, $y);&lt;br /&gt;            };&lt;br /&gt;&lt;br /&gt;        case 3:&lt;br /&gt;            switch ($op) {&lt;br /&gt;                case "+":&lt;br /&gt;                    return $x + $y;&lt;br /&gt;&lt;br /&gt;                case "-":&lt;br /&gt;                    return $x - $y;&lt;br /&gt;&lt;br /&gt;                default:&lt;br /&gt;                    throw new Exception("Invalid op");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;        default:&lt;br /&gt;            trigger_error("invalid argument count",&lt;br /&gt;                E_USER_WARNING);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;It's messy... but it works! Now you are able to pass one or two arguments to &lt;tt&gt;do_math()&lt;/tt&gt;, capture the intermediate function that's returned, and pass the remaining argument(s) later.&lt;br /&gt;&lt;pre&gt;$add = do_math("+");&lt;br /&gt;&lt;br /&gt;$inc = $add(1);&lt;br /&gt;$dec = $add(-1);&lt;br /&gt;&lt;br /&gt;echo do_math("-", 3, 2);&lt;br /&gt;echo do_math("+", 1, 1);&lt;br /&gt;echo $inc(2);&lt;br /&gt;echo $add(2, 2);&lt;br /&gt;echo $dec(6);&lt;br /&gt;echo $add($inc(4), $dec(2));&lt;br /&gt;&lt;/pre&gt;The &lt;tt&gt;switch&lt;/tt&gt; statements are rather unmanageable and the spaghettification of code grows exponentially with the addition of each argument. This pattern is straight forward, though. You may want to consider writing a code generator to handle the dirty work of retrofitting a function to one capable of being curried rather than writing them all by hand. Of course, if you know of a better way to curry functions in PHP then let me know by leaving a comment!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 06/29/09: &lt;/span&gt;Someone asked me what the "real-world use" for all this would be. Currying is used all the time in functional programming, but the hassle of explicitly enabling the behavior in PHP makes that a valid question. My motivation was just to see if it were possible and share my results. Indeed it is. Functions can be curried in any language that supports closures. But for those who want something a little more concrete, let's consider callback functions.&lt;br /&gt;&lt;br /&gt;In a &lt;a href="http://zaemis.blogspot.com/2009/03/anonymous-functions-and-closures.html"&gt;previous post&lt;/a&gt; I gave the following example to illustrate the use of closures:&lt;br /&gt;&lt;pre&gt;$userPercent = 0.5;&lt;br /&gt;$userList = array_filter($percentVowels,&lt;br /&gt;    function($percent) use ($userPercent) {&lt;br /&gt;        return ($percent &gt;= $userPercent); &lt;br /&gt;    });&lt;br /&gt;&lt;/pre&gt;It showed an anonymous function being used with &lt;tt&gt;array_filter()&lt;/tt&gt; to filter an array. The array is filtered based on a dynamic value, and a closure is used to "inject" the threshold rather than using a &lt;tt&gt;global&lt;/tt&gt; statement. The same could also be accomplished with currying. &lt;br /&gt;&lt;br /&gt;The problem is &lt;tt&gt;array_filter()&lt;/tt&gt; expects a callback function that accepts one argument--the current array element. Currying will allow us to prepare the function with the sorting threshold, and the intermediate function can be used as the callback.&lt;br /&gt;&lt;pre&gt;function callback($userPercent) {&lt;br /&gt;    return function($percent) use ($userPercent) {&lt;br /&gt;        return ($percent &gt;= $userPercent);&lt;br /&gt;    };&lt;br /&gt;}&lt;br /&gt;$userList = array_filter($percentVowels, callback(0.5));&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6929898231772447310?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6929898231772447310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/06/currying-in-php.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6929898231772447310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6929898231772447310'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/06/currying-in-php.html' title='Currying in PHP'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6749102202640007172</id><published>2009-06-14T22:33:00.003-04:00</published><updated>2009-06-28T23:58:59.284-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><title type='text'>Kember Identity</title><content type='html'>Ever wonder if there is an MD5 hash the same as the original input?  Nope, me neither.  But Mr. Kember does and he's asking the world to help him find out if such a thing exists.  There's no fame if you find it for him (he's humbly named it the "Kember Identity" already)—but you might make a little cash. Check out &lt;a href="http://elliottkember.com/kember_identity.html"&gt;his web page&lt;/a&gt; for the details. Go ahead and enter his contest if you're feeling &lt;s&gt;gullible&lt;/s&gt; lucky!&lt;br /&gt;&lt;br /&gt;The MD5 algorithm returns a fixed-length 128-bit hash, so there are 2&lt;sup&gt;128&lt;/sup&gt; possible values.  The hash is typically expressed as a series of 32 hexadecimal values.  Since the input string and its hash must be the same to reflect the Kember Identity, you wouldn't need to test random strings like "ruby on rails rots your brain"; you only need to test strings that are 32-characters long and contain the numbers 0 though 9 and letters a through f like &lt;nobr&gt;8d112b3c68248c12f178188c1b921ec1&lt;/nobr&gt;.&lt;br /&gt;&lt;br /&gt;Kember suggests testing values at random because the range of candidates is so large (2&lt;sup&gt;128&lt;/sup&gt; is &lt;nobr&gt;34,028,236,692,093,846,346,337,460,743,177&lt;/nobr&gt;). Unfortunately, there're a few problems with this approach:&lt;ul&gt;&lt;li&gt;Deterministic machines cannot &lt;a href="http://en.wikipedia.org/wiki/PRNG"&gt;generate truly random numbers&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Uniform_distribution_(continuous)"&gt;Reoccurring values&lt;/a&gt; in the sequence will cause an invalid hash to be rested&lt;/li&gt;&lt;br /&gt;&lt;li&gt;There are some values that may never be tested&lt;/li&gt;&lt;/ul&gt;It actually takes &lt;em&gt;less time&lt;/em&gt; to test all values sequentially than through random-selection.&lt;br /&gt;&lt;br /&gt;Additionally, one has to consider the possibility that such a value doesn't exist.  The odds of finding the Kember Identity are actually quite small: &lt;nobr&gt;&lt;a href="http://www.wikihow.com/Calculate-Lotto-Odds"&gt;1/((2&lt;sup&gt;128&lt;/sup&gt;!)/( 2&lt;sup&gt;128&lt;/sup&gt;!)(1-2&lt;sup&gt;128&lt;/sup&gt;)!)&lt;/a&gt;.&lt;/nobr&gt;  So how would you know when all possible values have been tested proving the Kember identity doesn't exist if the values are tested randomly? You don't.&lt;br /&gt;&lt;br /&gt;The only reliable way to programmatically identify whether the Kember Identity exists and what hashes exhibit it is to test each hashes sequentially and record the results.&lt;br /&gt;&lt;br /&gt;The whole thing might not bother me if money wasn't involved. Just send Mr. Kember your $5 entry fee and you're eligible to win the prize pot if your script is first to find the magical hash! But I have a few questions:&lt;ul&gt;&lt;li&gt;How do I contact Mr. Kember to receive my prize when I find a hash that exhibits the Kember Identity?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;What happens to my $5 and the rest of the prize money if it is proven the Identity doesn't exist?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;At 60-million hashes an hour, it would take over &lt;nobr&gt;646,987,670,262,051,588,140,743&lt;/nobr&gt; &lt;em&gt;millennia&lt;/em&gt; to verify them all.  How long does Mr. Kember plan on holding on to the prize money?&lt;/li&gt;&lt;/ul&gt;While it might not be a scam (it says explicitly that it's not a scam somewhere on the irrationally highlighted contest page), it isn't well thought out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6749102202640007172?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6749102202640007172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/06/kember-identity.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6749102202640007172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6749102202640007172'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/06/kember-identity.html' title='Kember Identity'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2730894236298615020</id><published>2009-06-11T00:02:00.012-04:00</published><updated>2010-12-05T14:36:03.059-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Language Design'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><title type='text'>What's Wrong with OOP</title><content type='html'>Proponents of Object Oriented Programming feel the paradigm yields code that is better organized, easier to understand and maintain, and reusable. They view procedural programming code as unwieldy spaghetti and embrace OO-centric design patterns as the "right way" to do things. They argue objects are easier to grasp because they model how we view the world. If the popularity of languages like Java and C# is any indication, they may be right. But after almost 20 years of OOP in the mainstream, there's still a large portion of programmers who resist it. If objects truly model the way people think of things in the real world, then why do people have a hard time understanding and working in OOP?&lt;br /&gt;&lt;br /&gt;I suspect the problem might be the focus on objects instead of actions. If I may quote from Steve Yegge's &lt;a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html"&gt;Execution in the Kingdom of Nouns&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Verbs in Javaland are responsible for all the work, but as they are held in contempt by all, no Verb is ever permitted to wander about freely. If a Verb is to be seen in public at all, it must be escorted at all times by a Noun.&lt;/blockquote&gt;&lt;br /&gt;OOP focuses primarily on the object and expresses actions in terms of the object's abilities. A airplane object can be flown (&lt;span style="font-family:courier new;"&gt;Airplane.fly()&lt;/span&gt;). A door object can be opened (&lt;span style="font-family:courier new;"&gt;Door.open()&lt;/span&gt;). But we really don't view the world in terms of objects and what actions can be done to them. It's backwards. We view the world in terms of ourselves and our abilities. We are the &lt;em&gt;ultimate object&lt;/em&gt;. (And no, I don't mean a &lt;a href="http://en.wikipedia.org/wiki/God_object"&gt;God object&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Imagine you are returning from a trip to the local flower garden. Would you say "I smelled the flowers" or "The flowers were smelled by me?" Now you want to tell a friend to go and smell the flowers. Would you say "Go and smell the flowers" or "The flowers must be smelled by you?"  When we convey instructions, we give them in terms relative to ourselves. What is programming but &lt;a href="http://mitpress.mit.edu/sicp/"&gt;conveying instructions to a computer process&lt;/a&gt; how some sort of work should be done on our behalf.&lt;br /&gt;&lt;br /&gt;How to make a Peanut Butter Sandwich:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Get Jar of Peanut Butter&lt;/li&gt;&lt;li&gt;Get Loaf of Bread&lt;/li&gt;&lt;li&gt;Get Knife&lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;All of these things (jar of peanut butter, bread, and knife) can be thought of as objects.&lt;br /&gt;&lt;pre&gt;class PeanutButterJar extends Jar ...&lt;br /&gt;&lt;/pre&gt;Express them as such and they take on methods.&lt;br /&gt;&lt;pre&gt;PeanutButterJar.open()&lt;br /&gt;Knife.spread(PeanutButter, Bread)&lt;br /&gt;&lt;/pre&gt;Whoa!  In my world, peanut butter doesn't do anything but sit there and taste yummy. And I'd start &lt;a href="http://answers.yahoo.com/question/index?qid=20090521170058AAIgZLy"&gt;looking for a good exorcist&lt;/a&gt; the moment a knife starts performing actions all by by itself. A more realistic transcription of the instructions would be:&lt;br /&gt;&lt;pre&gt;You.open(PeanutButterJar)&lt;br /&gt;You.spread(Knife, PeanutButter, Bread)&lt;br /&gt;&lt;/pre&gt;Specifying &lt;span style="font-family:courier new;"&gt;You&lt;/span&gt; as a universal object would seem rather redundant as the scenario progressed, so a good language designer would remove the need to expressly identify it.  This would yield&lt;br /&gt;&lt;pre&gt;open(PeanutButterJar)&lt;br /&gt;spread(Knife, PeanutButter, Bread)&lt;br /&gt;&lt;/pre&gt;which starts to look vaguely procedural.&lt;br /&gt;&lt;br /&gt;The truth is, procedural and OOP paradigms languages express the complexity of their problem space in different ways. Procedural code is flat and wide with functions. OO code is hierarchical with inheritance. OO-code is not inherently better organized than procedural code merely because it is encapsulated in objects. A reusable library can consist of functions just as easily as a collection of objects.&lt;br /&gt;&lt;br /&gt;The way some OOP languages (like Java and C#) force objects on the programmer borders on the absurd.  If I'm writing a library of reusable code that needs to maintain its own state, then of course writing classes with proper encapsulation and dating hiding makes sense. On the other hand, If I'm generating a web page with some data stored in a database, then some procedural code and a handful of function calls makes more sense. One of the things I like about PHP so much is that it allows the programmer to decide which paradigm is best suited for the task at hand.&lt;br /&gt;&lt;br /&gt;Sadly though, that decision isn't left to the programmer who has been tasked with developing and maintaining a system.  Management can tend to focus too much on buzzword compliance. A procedural programming language designed today would never receive wide-spread adoption if it didn't offer some sort of OO construct despite both paradigms having produced successful libraries and applications.  And the programmers that don't learn to think beyond themselves will be unfairly left in the dust.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2730894236298615020?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2730894236298615020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/06/whats-wrong-with-oop.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2730894236298615020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2730894236298615020'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/06/whats-wrong-with-oop.html' title='What&apos;s Wrong with OOP'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6554783934097847844</id><published>2009-04-28T01:14:00.003-04:00</published><updated>2009-09-26T22:28:52.059-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Predictions'/><title type='text'>Death Knell for MySQL</title><content type='html'>Someone asked me, "What do you think about the Oracle/Sun buyout as it pertains to MySQL?" Well, since you're asking...&lt;br /&gt;&lt;br /&gt;I thought it was bad for MySQL when Sun bought them despite what others were saying at the time.  It turns out I was right.  I think Oracle will be worse, and this time the blogosphere are saying it'll probably be bad. Now the question is, just how bad will it be?  Here's my predictions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I'm sure Oracle realizes they need to tread lightly on the subject of MySQL or else risk the wrath of the open source community.  They may integrate some of MySQL to improve Oracle, but they won't promote the continued development of MySQL proper (Berkeley DB anyone?).  That is, Oracle won't actively kill MySQL, but they'll let continue to languish the slow and painful death that began before Sun came along.  I don't see a financial benefit to Oracle for keeping MySQL healthy.  If MySQL does survive, it might be branded as "Oracle Lite."&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Core developers will continue work on MySQL in the form of Drizzle, a fork based on MySQL 6.0.  Drizzle's focus is on refactoring the MySQL code base and scaling down the feature set-- views, triggers, stored procedures, etc. will be available through modules but not in the core-- to providing a fast and efficient RDBMS for web-based and distributed applications.  Drizzle will become very popular as a MySQL alternative for dedicated community members and web developers, and enterprise users who require a larger feature set will migrate to PostgreSQL (and Pythonistas rejoice en masse).&lt;/li&gt;&lt;/ul&gt;If a commercial company buys control of an open-source project,   but then the project's community and core developers fork the codebase and continue development, then the company has effectively only purchased rights to a particular branch.  It's legal, but it's not a palatable situation for commercial corporations who might be looking to buy up open source applications.  I doubt we'll see Oracle starting a SCO-like court battle over MySQL... but we sure are living in interesting times. Welcome to the era of new law.&lt;br /&gt;&lt;br /&gt;I'm primarily a PHP developer so I'll most likely migrate to Drizzle if and when that time comes. A lot of what I do could probably be done with SQLite, but I don't particularly care for the way SQLite does some things. That's another story for another day...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6554783934097847844?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6554783934097847844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/04/death-knell-for-mysql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6554783934097847844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6554783934097847844'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/04/death-knell-for-mysql.html' title='Death Knell for MySQL'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2003767434888235439</id><published>2009-04-01T17:06:00.013-04:00</published><updated>2010-01-17T18:58:37.419-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Certification Failure</title><content type='html'>Some employers look favorably on certifications, or even require them; other employers could care less.  Some people are certified in something but clueless when it comes to actually using the technology.  Some people get certifications like they're going out of style just because they can.  Some people &lt;a href="http://www.sdtimes.com/link/33359"&gt;cheat on the exam&lt;/a&gt;.   So how much stock should one put in certifications?  I'm not sure I know the answer to that.  I guess it depends on the certification, what the testing environment is like, who runs the certification program, etc.&lt;br /&gt;&lt;br /&gt;Today I ran across &lt;a href="http://www.php-rocks.com/"&gt;PHP-Rocks&lt;/a&gt; during my daily web-surfing.  It's a small site that offers a set of tutorials ranging from beginner up to advanced, and a PHP "certification" exam.  The exam piqued my interest.  It was free to take, and I was curious as to what type of questions it asked, so I signed up.  Of course I often sign up a dummy account and fake email address when I do such things because I don't intend on becoming a regular visitor to the site, nor do I care to be placed on some spam mailing list.  I chose "Joe Biteme" as my name for this excursion.&lt;br /&gt;&lt;br /&gt;I answered randomly, not taking the exam seriously (like I said, I was more interested in what type of questions they were asking rather than actually getting their "certification").  I utterly failed it with a miserable 26.6667%!  But I figure if they don't feel guilty about offering me the opportunity to pay them $5 to email me the certificate for a failed exam, then I probably shouldn't feel guilty about making a mockery of their exam process (and perhaps even the exam itself) by registering a fake identity and answering randomly.&lt;br /&gt;&lt;br /&gt;Click on the image below to enlarge it and you'll see I successfully completed the PHP developer exam with a &lt;b&gt;fail&lt;/b&gt;!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.saltcitytech.com/%7Etboronczyk/blogger/certfail.jpg"&gt;&lt;img style="border-width: 1px; margin: 0px auto 10px; display: block; text-align: center; width: 400px;" src="http://www.saltcitytech.com/blogger/certfail.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;In full disclosure, yes I took (and passed) the &lt;a href="http://www.zend.com/en/store/php-certification/exam-voucher"&gt;Zend Certified Engineer&lt;/a&gt; exam for PHP5 offered by Zend, and yes I took it much more seriously than I did PHP-Rock's exam.  Also, it's not my purpose to single out a particular web site... I just found their snafu too humorous not to share.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2003767434888235439?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2003767434888235439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/04/certification-failure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2003767434888235439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2003767434888235439'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/04/certification-failure.html' title='Certification Failure'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-2867255091654705613</id><published>2009-03-19T21:41:00.010-04:00</published><updated>2009-03-24T13:56:44.582-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Goto and Exceptions</title><content type='html'>It slipped quietly under the radar for some. For others, it raised quite a stir. No, I'm not talking about PHP's implementation of namespaces (a battle that's finally done and over much to everyone's relief). I'm referring to the infamous &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; statement.&lt;br /&gt;&lt;br /&gt;Many programmers have had the "&lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; is evil" mantra drilled into them from an early start. The basis of this can probably be traced back to Edsger Dijkstra's &lt;a href="http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF"&gt;March 1968 letter to the editor&lt;/a&gt; in &lt;em&gt;Communications of the ACM&lt;/em&gt; (though he wasn't the first to argue against &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt;). Dijkstra felt the proliferation of &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; at the time was producing unmaintainable "spaghetti" code. Fast-forward more than 40 years later and the controversial feature is still alive and well... and about to make its debut appearance in PHP.&lt;br /&gt;&lt;br /&gt;I found myself discussing some of the new features in PHP 5.3 with a friend a few days ago after he read my previous post about &lt;a href="http://zaemis.blogspot.com/2009/03/anonymous-functions-and-closures.html"&gt;anonymous functions and closures&lt;/a&gt;. Our conversation eventually turned towards &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; and whether it was possible or not to use it responsibly.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; re-routes the execution flow of a program from one section of its code to another. Even the most basic control structures like &lt;span style="font-family:courier new;"&gt;if&lt;/span&gt; wouldn't exist in high-level languages like C, Java, and even PHP, if it weren't for some type of &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt;-like operation (high-level languages are either implemented in low-level languages like x86 Assembler which has the equivalent operation &lt;span style="font-family:courier new;"&gt;JMP&lt;/span&gt;, or are implemented in other high-level languages which in turn are implemented in low-level languages). Constructs like conditional statements, loops, and functions all ultimately reduce down to a &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; operation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; itself isn't much of a necessity in high-level languages because dedicated constructs like conditional statements, loops, etc. are available to the programmer, and these are much easier for humans to work with than goto. Yet &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; can still be useful under certain circumstances. For example, some programmers use &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; to direct the execution flow to dedicated error-handling logic elsewhere in a program in languages that lack exception handling (such as C).&lt;br /&gt;&lt;br /&gt;So is it possible to use &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; responsibly in high-level languages, particularly in PHP? I've drawn the conclusions that it is indeed possible:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;to emulate exception handling in a procedural environment (otherwise good, but not if the language supports offers real exception handling which PHP does)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;to overcome some of the perceived limitations in the try/catch exception handling model often found in an OOP environment (useful and arguably good because the alternatives can lead to fragile code)&lt;/li&gt;&lt;/ul&gt;Let's start right in by comparing some sample code to decide if using &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; to emulate exceptions is responsible use. (Everyone loves code, right?) Here's a function with the error-handling code interspersed throughout it:&lt;br /&gt;&lt;pre&gt;// return an array of employees, else -1 on error&lt;br /&gt;function retrieveEmployees()&lt;br /&gt;{&lt;br /&gt;    // assume DB_HOSTNAME et al are defined elsewhere as &lt;br /&gt;    // constants&lt;br /&gt;    $db = mysql_connect(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);&lt;br /&gt;    if ($db === false) {&lt;br /&gt;        echo "Unable to connect to database server.";&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    $success = mysql_select_db(DB_SCHEMA);&lt;br /&gt;    if (!$success) {&lt;br /&gt;        mysql_close($db);&lt;br /&gt;        echo "Unable to select database.";&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    $query = "SELECT id, last_name, first_name FROM employees&lt;br /&gt;        ORDER BY last_name ASC, first_name ASC";&lt;br /&gt;    $result = mysql_query($query, $db);&lt;br /&gt;    if ($result === false) {&lt;br /&gt;        mysql_close($db);&lt;br /&gt;        echo "Unable to execute query.";&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    $employees = array();&lt;br /&gt;    while ($row = mysql_fetch_assoc($result)) {&lt;br /&gt;        $employees[] = $row;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    mysql_close($db);&lt;br /&gt;    return $employees;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now, here's the same function refactored to use &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt;. The actual error-handling code has been moved to the end of the function, where it is out of the way of a programmer trying to read through the function's code and to understand its purpose.&lt;br /&gt;&lt;pre&gt;function retrieveEmployees()&lt;br /&gt;{&lt;br /&gt;    $db = mysql_connect(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);&lt;br /&gt;    if ($db === false) goto CONNECT_ERROR;&lt;br /&gt;&lt;br /&gt;    $success = mysql_select_db(DB_SCHEMA);&lt;br /&gt;    if (!$success) goto SCHEMA_ERROR;&lt;br /&gt;&lt;br /&gt;    $query = "SELECT id, last_name, first_name FROM employees&lt;br /&gt;        ORDER BY last_name ASC, first_name ASC";&lt;br /&gt;    $result = mysql_query($query, $db);&lt;br /&gt;    if ($result === false) goto QUERY_ERROR;&lt;br /&gt;&lt;br /&gt;    $employees = array();&lt;br /&gt;    while ($row = mysql_fetch_assoc($result)) {&lt;br /&gt;        $employees[] = $row;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    mysql_close($db);&lt;br /&gt;    return $employees;&lt;br /&gt;&lt;br /&gt;    // possible errors&lt;br /&gt;    CONNECT_ERROR:&lt;br /&gt;        echo "Unable to connect to database server.";&lt;br /&gt;        return -1;&lt;br /&gt;&lt;br /&gt;    SCHEMA_ERROR:&lt;br /&gt;        mysql_close($db);&lt;br /&gt;        echo "Unable to select database.";&lt;br /&gt;        return -1;&lt;br /&gt;&lt;br /&gt;    QUERY_ERROR:&lt;br /&gt;        mysql_close($db);&lt;br /&gt;        echo "Unable to execute query.";&lt;br /&gt;        return -1;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The use of &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; in this case makes it arguably easier to follow the logic and understand the purpose of &lt;span style="font-family:courier new;"&gt;retrieveEmployees()&lt;/span&gt; because you no longer have to visually sift through code chafe to find the proverbial wheat.&lt;br /&gt;&lt;br /&gt;Incidentally, this is the same goal of exceptions-- move error handling to make the code easier to understand. PHP has supported exceptions since the nascent days of PHP 5, so let's refactor the code again. This time I'll make use of exceptions.&lt;br /&gt;&lt;pre&gt;// extend Exception class&lt;br /&gt;class ConnectErrorException extends Exception { }&lt;br /&gt;class SchemaErrorException extends Exception { }&lt;br /&gt;class QueryErrorException extends Exception { }&lt;br /&gt;&lt;br /&gt;function retrieveEmployees()&lt;br /&gt;{&lt;br /&gt;    try {&lt;br /&gt;        $db = mysql_connect(DB_HOSTNAME, DB_USERNAME, &lt;br /&gt;            DB_PASSWORD);&lt;br /&gt;        if ($db === false) throw new ConnectErrorException();&lt;br /&gt;&lt;br /&gt;        $success = mysql_select_db(DB_SCHEMA);&lt;br /&gt;        if (!$success) throw new SchemaErrorException();&lt;br /&gt;&lt;br /&gt;        $query = "SELECT id, last_name, first_name FROM&lt;br /&gt;            employees ORDER BY last_name ASC, first_name ASC";&lt;br /&gt;        $result = mysql_query($query, $db);&lt;br /&gt;        if ($result === false) throw new QueryErrorException();&lt;br /&gt;&lt;br /&gt;        $employees = array();&lt;br /&gt;        while ($row = mysql_fetch_assoc($result)) {&lt;br /&gt;            $employees[] = $row;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        mysql_close($db);&lt;br /&gt;        return $employees;&lt;br /&gt;    }&lt;br /&gt;    catch (ConnectErrorException $e) {&lt;br /&gt;        echo "Unable to connect to database server.";&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;    catch (SchemaErrorException $e) {&lt;br /&gt;        mysql_close($db);&lt;br /&gt;        echo "Unable to select database.";&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;    catch (QueryErrorException $e) {&lt;br /&gt;        mysql_close($db);&lt;br /&gt;        echo "Unable to execute query.";&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Comparing the second and third iterations of &lt;span style="font-family:courier new;"&gt;retrieveEmployees()&lt;/span&gt;, one could argue that using &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; results in a cleaner syntax than actual exception handling. With &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt;, the programmer doesn't need to extend the base &lt;span style="font-family:courier new;"&gt;Exception&lt;/span&gt; class, position the code in question within a &lt;span style="font-family:courier new;"&gt;try&lt;/span&gt;/&lt;span style="font-family:courier new;"&gt;catch&lt;/span&gt; blocks, and make sure all of the braces were matched correctly. Instead, the programmer only has to provide a target label and the actual &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; call.&lt;br /&gt;&lt;br /&gt;Without the overhead of instantiating an &lt;span style="font-family:courier new;"&gt;Exception&lt;/span&gt;object, there's also a slight performance boost. The results of a highly (un-)scientific benchmark I ran to compare &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; error-handling against exceptions using the above examples showed &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; is a little over 4% faster.&lt;br /&gt;&lt;br /&gt;Unfortunately, those benefits are meager when you take a closer look and see the drawbacks of using &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt;. Exceptional events allow the programmer to signal than an error occurred, but &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; is a direct jump to the error handling logic. Each label must be unique. The programmer may soon find himself duplicating code and devising creative label names to handle the same type of errors in slightly different ways. Another drawback is that PHP requires the label to be within the same scope as the &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; call. This means the following code will generate a fatal error:&lt;br /&gt;&lt;pre&gt;function generateError()&lt;br /&gt;{&lt;br /&gt;    goto GENERATED_ERROR;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GENERATED_ERROR:&lt;br /&gt;    die("Oops!");&lt;br /&gt;&lt;/pre&gt;Exceptions can offer more flexibility since the thrown exception bubbles up the call stack until it is caught by a suitable &lt;span style="font-family:courier new;"&gt;catch&lt;/span&gt; block:&lt;br /&gt;&lt;pre&gt;class GeneratedErrorException extends Exception { }&lt;br /&gt;&lt;br /&gt;function generateError()&lt;br /&gt;{&lt;br /&gt;    throw new GeneratedErrorException();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;    generateError();&lt;br /&gt;}&lt;br /&gt;catch (GeneratedErrorException $e) {&lt;br /&gt;    die("Oops!");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Exceptions were designed explicitly for the purpose of error-handling. There's only one way to get into the error-handling code of a &lt;span style="font-family:courier new;"&gt;catch&lt;/span&gt; block-- by a &lt;span style="font-family:courier new;"&gt;throw&lt;/span&gt; call. The code that follows a &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; label on the other hand can be executed as part of the normal flow of execution, or as a backwards redirect. Exceptions have their own dissidents, but even so they don't have nearly the bad rap that &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; does. Using &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; will probably draw the wrath of many anti-&lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; programmers upon you faster than a speeding photon, while using exceptions will win you job interviews.&lt;br /&gt;&lt;br /&gt;The conclusion for my first talking point is that using &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; to emulate exceptions is useful, but it's better to use exceptions instead of faking things if the language provides them (which PHP does).&lt;br /&gt;&lt;br /&gt;Exceptions are well suited to the event-driven execution model where the execution flow is determined by events (such as the user clicking on a graphical interface component or pressing a key on the computer). The runtime loop waits for something to happen, possibly for an infinite amount of time, and then executes the logic assigned by the programmer to an appropriate action when it detects an event. If there is a problem that will prevent the action from being completed successfully then an exception can handle it, terminate that thread, and return the flow to the main wait-state. Users can fix the problem and try again without the program terminating.&lt;br /&gt;&lt;br /&gt;Unfortunately, PHP doesn't enjoy this execution model, and it's been my experience that exceptions are just as easy to abuse when used in batch/imperative models as &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; is. All too often a programmer will catch the exception and then simply terminate the program. &lt;br /&gt;&lt;pre&gt;class FileAccessException extends Exception { }&lt;br /&gt;&lt;br /&gt;$filename = "test.txt";&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;    $fp = @fopen($filename, "r");&lt;br /&gt;    if ($fp === false) {&lt;br /&gt;        throw new FileAccessException("cannot open $filename");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;catch (FileAccessException $e) {&lt;br /&gt;    die("Error: " . $e-&gt;getMessage());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Is this really effective error handling? It might be if the script is processing a batch job or generating a web page. There is nothing the requestor can do in those cases to address whatever it is that caused the error, and the only reasonable course of action is to gracefully terminate the script. But what if the script were running interactively from a command prompt? PHP is primarily used to generate web content, but as more and more people realize its flexibility and the benefits of reducing the number of programming language across all parts of an application, CLI scripting with PHP is becoming more popular. In that case, a more proper action for the script to take would be to inform its users what the error was and suggest some possible steps they can take to resolve it.&lt;br /&gt;&lt;pre&gt;// return whether the script is allowed read access ("r"),&lt;br /&gt;// or write access ("w") a file&lt;br /&gt;function testPermission($filename, $access = "r")&lt;br /&gt;{&lt;br /&gt;    clearstatcache();&lt;br /&gt;    list(,,$mode,,$uid,$gid) = stat($filename);&lt;br /&gt;    $perms = array("u_r" =&gt; (bool)($mode &amp; 0400),&lt;br /&gt;                   "u_w" =&gt; (bool)($mode &amp; 0200),&lt;br /&gt;                   "g_r" =&gt; (bool)($mode &amp; 0040),&lt;br /&gt;                   "g_w" =&gt; (bool)($mode &amp; 0020),&lt;br /&gt;                   "o_r" =&gt; (bool)($mode &amp; 0004),&lt;br /&gt;                   "o_w" =&gt; (bool)($mode &amp; 0002));&lt;br /&gt;    list($user) = posix_getpwuid($uid);&lt;br /&gt;    $group = posix_getgrgid($gid);&lt;br /&gt;&lt;br /&gt;    list($eUser) = posix_getpwuid(posix_geteuid());&lt;br /&gt;    $isUser = ($user == $eUser);&lt;br /&gt;    $isGroup = in_array($eUser, $group["members"]);&lt;br /&gt;    $isOther = !($isUser || $isGroup);&lt;br /&gt;&lt;br /&gt;    return (($isUser  &amp;&amp; $perms["u_" . $access]) ||&lt;br /&gt;            ($isGroup &amp;&amp; $perms["g_" . $access]) ||&lt;br /&gt;            ($isOther &amp;&amp; $perms["o_" . $access]));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;    $fp = @fopen($filename, "r");&lt;br /&gt;    if ($fp === false) {&lt;br /&gt;        throw new FileAccessException();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;catch (FileAccessException $e) {&lt;br /&gt;    if (!file_exists($filename)) {&lt;br /&gt;        die("$filename does not exist. Please create the " .&lt;br /&gt;            "file.\n");&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;        if (!testPermission($filename, "r")) {&lt;br /&gt;            die("Please check read permissions on " .&lt;br /&gt;                "$filename.\n");&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            die("Unknown error attempting to access " .&lt;br /&gt;                "$filename.\n");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The code is a bit smarter now about the error and offers users some guidance as to what needs to be done to resolve it, but the program still terminates. Not all exceptions should be fatal. In this case, it would be better for the code to give the users an opportunity to fix the error and then try to re-read the file instead of forcing them to start the program over again.&lt;br /&gt;&lt;br /&gt;Whereas in event-driven execution users can simply retry the action, there is no clean way to retry the code that triggered the error procedurally. One possibility is to surround the action in a &lt;span style="font-family:courier new;"&gt;do&lt;/span&gt;/&lt;span style="font-family:courier new;"&gt;while&lt;/span&gt; loop.&lt;br /&gt;&lt;pre&gt;// prompt the user whether to retry an action&lt;br /&gt;function promptRetry()&lt;br /&gt;{&lt;br /&gt;    do {&lt;br /&gt;        echo "Type 'R' to retry or 'Q' to quit: ";&lt;br /&gt;        $retry = strtoupper(trim(fread(STDIN, 2)));&lt;br /&gt;        if ($retry == "R") {&lt;br /&gt;            return true;&lt;br /&gt;        }&lt;br /&gt;        else if ($retry == "Q") {&lt;br /&gt;            return false;&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            echo "Invalid entry. ";&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    while (true);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;do {&lt;br /&gt;    $retry = false;&lt;br /&gt;    try {&lt;br /&gt;        $fp = @fopen($filename, "r");&lt;br /&gt;        if ($fp === false) {&lt;br /&gt;            throw new FileAccessException();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    catch (FileAccessException $e) {&lt;br /&gt;        if (!file_exists($filename)) {&lt;br /&gt;            echo "$filename does not exist. Please create " .&lt;br /&gt;                "the file.\n";&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            if (!testPermission($filename, "r")) {&lt;br /&gt;                echo "Please check read permissions on " .&lt;br /&gt;                    "$filename.\n";&lt;br /&gt;            }&lt;br /&gt;            else {&lt;br /&gt;                echo "Unknown error attempting to access " .&lt;br /&gt;                    "$filename.\n";&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        if (!promptRetry()) exit();&lt;br /&gt;        $retry = true;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;while ($retry);&lt;br /&gt;&lt;/pre&gt;I don't like how the &lt;span style="font-family:courier new;"&gt;$retry&lt;/span&gt; variable is set within the &lt;span style="font-family:courier new;"&gt;catch&lt;/span&gt; block to trigger the reiteration of the surrounding &lt;span style="font-family:courier new;"&gt;do&lt;/span&gt;/&lt;span style="font-family:courier new;"&gt;while&lt;/span&gt; loop. It seems a bit fragile to set variables within &lt;span style="font-family:courier new;"&gt;catch&lt;/span&gt; blocks in order to influence the behavior of code outside the block. Instead, the example can be refactored to use &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt;. This eliminates having to keep track of &lt;span style="font-family:courier new;"&gt;$retry&lt;/span&gt; altogether and just redirects the execution flow itself.&lt;br /&gt;&lt;pre&gt;TRY_OPEN_FILE:&lt;br /&gt;try {&lt;br /&gt;    $fp = @fopen($filename, "r");&lt;br /&gt;    if ($fp === false) {&lt;br /&gt;        throw new FileAccessException();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;catch (FileAccessException $e) {&lt;br /&gt;    if (!file_exists($filename)) {&lt;br /&gt;        echo "$filename does not exist. Please create " .&lt;br /&gt;            "the file.\n";&lt;br /&gt;    }&lt;br /&gt;    else if (!testPermission($filename, "r")){&lt;br /&gt;        echo "Please check write permissions on " .&lt;br /&gt;             "$filename.\n";&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;        echo "Unknown error attempting to access " .&lt;br /&gt;            "$filename.\n";&lt;br /&gt;    }&lt;br /&gt;    if (!promptRetry()) exit();&lt;br /&gt;    goto TRY_OPEN_FILE;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The conclusion on my second talking point was that &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; can be used to overcome some of the perceived limitations of working with exceptions in a batch/procedural execution model. Without the support of an event-driven execution model, and without a dedicated &lt;span style="font-family:courier new;"&gt;retry&lt;/span&gt;-type statement, programmers need to resort to looping constructs. The code that results can be brittle and difficult to maintain over time. &lt;span style="font-family:courier new;"&gt;goto&lt;/span&gt; offers an eloquent and succinct alternative.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-2867255091654705613?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/2867255091654705613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/03/goto-and-exceptions.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2867255091654705613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/2867255091654705613'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/03/goto-and-exceptions.html' title='Goto and Exceptions'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-1916317657193814587</id><published>2009-03-07T00:40:00.008-05:00</published><updated>2009-03-07T01:13:18.916-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Anonymous Functions and Closures</title><content type='html'>Of all the new goodies that are promised in PHP 5.3, the two which I think I am the most excited about are anonymous functions and closures.&lt;br /&gt;&lt;br /&gt;Anonymous functions are functions that are defined without being bound to a proper name. Typically, anonymous functions are used only a limited number of times and for a specific purpose; you could think of them as "throw-away" functions if you'd like.&lt;br /&gt;&lt;br /&gt;Let's consider the following example which illustrates a standard function used as a callback:&lt;br /&gt;&lt;pre&gt;function percentVowels_callback($word) {&lt;br /&gt;    $word = strtolower($word);&lt;br /&gt;    $chars = count_chars($word);&lt;br /&gt;    $numVowels = 0;&lt;br /&gt;    foreach (array("a", "e", "i", "o", "u") as $vowel) {&lt;br /&gt;        $numVowels += $chars[ord($vowel)];&lt;br /&gt;    }&lt;br /&gt;    return $numVowels / strlen($word);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$animals = array("aardvark", "elephant", "iguana", "orangutan",&lt;br /&gt;    "urchin");&lt;br /&gt;$percentVowels = array_map("percentVowels_callback", $animals);&lt;br /&gt;&lt;/pre&gt;The &lt;span style="font-family:courier new;"&gt;array_map()&lt;/span&gt; function accepts the name of a function and an array, and produces a new array resulting from applying the callback function to each element of the input array. The callback function I've defined accepts a string and returns the percentage of which is made up of vowels. For the sake of simplicity, I am only considering the letters &lt;em&gt;A&lt;/em&gt;, &lt;em&gt;E&lt;/em&gt;, &lt;em&gt;I&lt;/em&gt;, &lt;em&gt;O&lt;/em&gt; and &lt;em&gt;U&lt;/em&gt; to be vowels, even though sometimes &lt;em&gt;Y&lt;/em&gt; and rarely even &lt;em&gt;W&lt;/em&gt; can be treated as vowels as well.&lt;br /&gt;&lt;br /&gt;Since the function is only used once by this &lt;span style="font-family:courier new;"&gt;array_map()&lt;/span&gt; statement, it may make sense to refactor &lt;span style="font-family:courier new;"&gt;percentVowels_callback()&lt;/span&gt; as an anonymous function. Typically the purpose of a function is to eliminate repetitive code and build reusable components... but the purpose of anonymous functions is different.  Anonymous functions group together a related set of statements.&lt;br /&gt;&lt;br /&gt;Earlier versions of PHP (starting at version 4.0.1) provided limited support for defining anonymous functions with &lt;span style="font-family:courier new;"&gt;create_function()&lt;/span&gt;.  Here's an example which shows the call to &lt;span style="font-family:courier new;"&gt;array_map()&lt;/span&gt; with &lt;span style="font-family:courier new;"&gt;percentVowels_callback()&lt;/span&gt; refactored as an anonymous function using this &lt;span style="font-family:courier new;"&gt;create_function()&lt;/span&gt;.&lt;br /&gt;&lt;pre&gt;$percentVowels_callback = create_function('$word', '&lt;br /&gt;    $word = strtolower($word);&lt;br /&gt;    $chars = count_chars($word);&lt;br /&gt;    $numVowels = 0;&lt;br /&gt;    foreach (array("a", "e", "i", "o", "u") as $vowel) {&lt;br /&gt;        $numVowels += $chars[ord($vowel)];&lt;br /&gt;    }&lt;br /&gt;    return $numVowels / strlen($word);');&lt;br /&gt;&lt;br /&gt;$percentVowels = array_map($percentVowels_callback, $animals);&lt;br /&gt;&lt;/pre&gt;Depending on your preference and coding style, the callback can be defined inline, as well. Depending on how the application is organized, you may need to jump to a different section of the code file or to a different file all together to inspect the contents of the function when you are tracing through code, and then find your way back afterwards to the calling location. The function's body can be available visually where it is most pertinent.&lt;br /&gt;&lt;pre&gt;$percentVowels = array_map(create_function('$word', '&lt;br /&gt;    $word = strtolower($word);&lt;br /&gt;    $chars = count_chars($word);&lt;br /&gt;    $numVowels = 0;&lt;br /&gt;    foreach (array("a", "e", "i", "o", "u") as $vowel) {&lt;br /&gt;        $numVowels += $chars[ord($vowel)];&lt;br /&gt;    }&lt;br /&gt;    return $numVowels / strlen($word);'), $animals);&lt;br /&gt;&lt;/pre&gt;The &lt;span style="font-family:courier new;"&gt;create_function()&lt;/span&gt; function accepts two strings--the first listing the variable names to serve as the anonymous function's arguments, the second containing the code for the function's body--and returns a unique string which can be used to identify the function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;create_function()&lt;/span&gt; does have a few drawbacks, though. Because the argument list and function body are provided as strings, you must be careful to make sure certain characters within the string are escaped properly. You need to escape any single-quotation marks that appear if your strings are single-quoted, or you need to escape double-quotation marks and dollar signs if your strings are double-quoted.  Moreover, you also lose the benefits of any syntax highlighting your IDE may provide since it highlights the strings as... well, strings! Overall, the approach is cumbersome and clunky.&lt;br /&gt;&lt;br /&gt;As of version 5.3, PHP will offer better support for anonymous functions and a new syntax which supports closures.  The new syntax for anonymous functions is more similar to the manner in which JavaScript and other event-driven languages define them.&lt;br /&gt;&lt;pre&gt;$percentVowels_callback = function($word) {&lt;br /&gt;    $word = strtolower($word);&lt;br /&gt;    $chars = count_chars($word);&lt;br /&gt;    $numVowels = 0;&lt;br /&gt;    foreach (array("a", "e", "i", "o", "u") as $vowel) {&lt;br /&gt;        $numVowels += $chars[ord($vowel)];&lt;br /&gt;    }&lt;br /&gt;    return $numVowels / strlen($word);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;$percentVowels = array_map($percentVowels_callback, $animals);&lt;br /&gt;&lt;/pre&gt;Gone is the clumsiness of &lt;span style="font-family:courier new;"&gt;create_function()&lt;/span&gt; and its string arguments.  The anonymous function's arguments and body are provided as PHP code which can be highlighted correctly by your IDE. The one caveat to the new syntax is that there MUST be a trailing semi-colon after the function's closing brace, as &lt;span style="font-family:courier new;"&gt;$percentVowels_callback = &lt;em&gt;some value&lt;/em&gt;&lt;/span&gt; is a regular assignment statement.&lt;br /&gt;&lt;br /&gt;One is also able to define the anonymous function using the new syntax inline as well.&lt;br /&gt;&lt;pre&gt;$percentVowels = array_map(function ($word) {&lt;br /&gt;    $word = strtolower($word);&lt;br /&gt;    $chars = count_chars($word);&lt;br /&gt;    $numVowels = 0;&lt;br /&gt;    foreach (array("a", "e", "i", "o", "u") as $vowel) {&lt;br /&gt;        $numVowels += $chars[ord($vowel)];&lt;br /&gt;    }&lt;br /&gt;    return $numVowels / strlen($word);}, $animals);&lt;br /&gt;&lt;/pre&gt;So far I've shown you a rather uninspired example using an anonymous function, so let's expand it a bit and make things more interesting.  Suppose the application should reduce the list of percentages to those that are equal to or greater than a user-specified value. For this we can use &lt;span style="font-family:courier new;"&gt;array_filter()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family:courier new;"&gt;array_filter()&lt;/span&gt; function accepts an input array and the name of a function, and produces a new array resulting from applying the callback function to each element of the input array. If the callback returns true then the element tested is included in the final output array. We have a slight problem, though-- the documentation for &lt;span style="font-family:courier new;"&gt;array_filter()&lt;/span&gt; shows it only passes one value to the callback (the current array element to be examined). We need access to user-specified value as well.  Closures will allow us to "reach out" outside the scope of the &lt;span style="font-family:courier new;"&gt;percentFilter_callback()&lt;/span&gt; function to see the value of &lt;span style="font-family:courier new;"&gt;$userPercent&lt;/span&gt;.&lt;br /&gt;&lt;pre&gt;$userPercent = 0.5;&lt;br /&gt;$userList = array_filter($percentVowels,&lt;br /&gt;    function($percent) use ($userPercent) {&lt;br /&gt;        return ($percent &amp;gt;= $userPercent); &lt;br /&gt;    });&lt;br /&gt;&lt;/pre&gt;Closures allow you controlled access to values to the parent scope of a function. The new syntax introduces the use keyword to specify which variables should be imported. The anonymous function is passed the current element of the &lt;span style="font-family:courier new;"&gt;$percentVowels&lt;/span&gt; array by &lt;span style="font-family:courier new;"&gt;array_filter()&lt;/span&gt;, but it has access to the value of &lt;span style="font-family:courier new;"&gt;$userPercent&lt;/span&gt; as well which is needed for the comparison.&lt;br /&gt;&lt;br /&gt;Closures in PHP import the variable from the parent scope the same as if it were passed as an argument to the function and manipulating the variable does not have an effect outside the function (unless it was passed by reference).&lt;br /&gt;&lt;br /&gt;However, it is important to keep in mind that closure is not the same thing as using &lt;span style="font-family:courier new;"&gt;global&lt;/span&gt;. &lt;span style="font-family:courier new;"&gt;global&lt;/span&gt; reference variables within the global scope of the script. Closures on the other hand can only bind to variables in the parent scope of a function, which make using them considerably safer than using &lt;span style="font-family:courier new;"&gt;global&lt;/span&gt;.  I'll leave you with this final example which highlights this difference between them:&lt;br /&gt;&lt;pre&gt;$x = 42;&lt;br /&gt;&lt;br /&gt;function foo() {&lt;br /&gt;    function fizz() {&lt;br /&gt;        global $x;&lt;br /&gt;        echo $x;&lt;br /&gt;    }&lt;br /&gt;    bar();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function bar() {&lt;br /&gt;    $bizz = function () use ($x) { echo $x; };&lt;br /&gt;    $bizz();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;For more information on anonymous functions and closures, check out these pages:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.php.net/rfc/closures"&gt;http://wiki.php.net/rfc/closures&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Anonymous_function"&gt;http://en.wikipedia.org/wiki/Anonymous_function&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.defmacro.org/ramblings/fp.html"&gt;http://www.defmacro.org/ramblings/fp.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.jibbering.com/faq/faq_notes/closures.html"&gt;http://www.jibbering.com/faq/faq_notes/closures.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-1916317657193814587?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/1916317657193814587/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/03/anonymous-functions-and-closures.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1916317657193814587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1916317657193814587'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/03/anonymous-functions-and-closures.html' title='Anonymous Functions and Closures'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-1831927960243825539</id><published>2009-01-20T23:22:00.019-05:00</published><updated>2009-03-07T01:07:40.847-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Evil Access</title><content type='html'>I was thinking today about database APIs when inspiration struck. I ended up hacking out the following class, which I think demonstrates a rather interesting approach to interfacing with a database (interesting enough at least to post here).&lt;br /&gt;&lt;pre&gt;class DBQuery implements Iterator&lt;br /&gt;{&lt;br /&gt;    protected $_db;&lt;br /&gt;    protected $_query;&lt;br /&gt;    protected $_result;&lt;br /&gt;    protected $_index;&lt;br /&gt;    protected $_num_rows;&lt;br /&gt;    &lt;br /&gt;    public function __construct($host, $dbname, $username,&lt;br /&gt;        $password) {&lt;br /&gt;        $this-&amp;gt;_db = new PDO("mysql:dbname=$dbname;host=$host",&lt;br /&gt;        $username, $password);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function __get($query) {&lt;br /&gt;        $this-&amp;gt;_query = $query;&lt;br /&gt;        $this-&amp;gt;_result = $this-&amp;gt;_db-&amp;gt;query($query);&lt;br /&gt;        return $this-&amp;gt;_num_rows = $this-&amp;gt;_result-&amp;gt;rowCount();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function quote($value) {&lt;br /&gt;        return PDO::quote($value);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function __call($query, $values) {&lt;br /&gt;        $this-&amp;gt;_query = $query;&lt;br /&gt;        $this-&amp;gt;_result = $this-&amp;gt;_db-&amp;gt;prepare($this-&amp;gt;_query);&lt;br /&gt;        $this-&amp;gt;_result-&amp;gt;execute($values[0]);&lt;br /&gt;        return $this-&amp;gt;_num_rows = $this-&amp;gt;_result-&amp;gt;rowCount();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function clear() {&lt;br /&gt;        $this-&amp;gt;_index = 0;&lt;br /&gt;        $this-&amp;gt;_num_rows = 0;&lt;br /&gt;        $this-&amp;gt;_query = '';&lt;br /&gt;        $this-&amp;gt;_result-&amp;gt;closeCursor();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function rewind() {&lt;br /&gt;        $this-&amp;gt;_index = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function current() {&lt;br /&gt;        return $this-&amp;gt;_result-&amp;gt;fetch(PDO::FETCH_ASSOC,&lt;br /&gt;            PDO::FETCH_ORI_ABS, $this-&amp;gt;_index);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function key() {&lt;br /&gt;        return $this-&amp;gt;_index;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function next() {&lt;br /&gt;        $this-&amp;gt;_index++;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function valid() {&lt;br /&gt;        return ($this-&amp;gt;_index &amp;lt; $this-&amp;gt;_num_rows);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function __toString() {&lt;br /&gt;        return $this-&amp;gt;_query;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-family:courier new;"&gt;DBQuery&lt;/span&gt; isn't your typical database access class. In fact, I would suggest it's slightly evil since it distorts traditional PHP syntax by abusing taking advantage of three specific PHP features.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;PHP allows special characters in an identifier if the string is quoted and is enclosed by &lt;span style="font-family:courier new;"&gt;{}&lt;/span&gt;. So, &lt;span style="font-family:courier new;"&gt;$myValue&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;&lt;nobr&gt;${"my value"}&lt;/nobr&gt;&lt;/span&gt; are both equally valid variable identifiers.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The magic overloading methods allow you handle undefined properties and methods in your class. Specifically, I've made use of &lt;span style="font-family:courier new;"&gt;__get()&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;__call()&lt;/span&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;A class that implements the &lt;span style="font-family:courier new;"&gt;Iterator&lt;/span&gt; interface can be traversed using a &lt;span style="font-family:courier new;"&gt;foreach&lt;/span&gt; loop.&lt;/li&gt;&lt;/ol&gt;Here's a look at how &lt;span style="font-family:courier new;"&gt;DBQuery&lt;/span&gt; would be used:&lt;br /&gt;&lt;pre&gt;// connect to the database&lt;br /&gt;$dbq = new DBQuery("localhost", "test", "dbuser",&lt;br /&gt;    "dbpassword");&lt;br /&gt;&lt;br /&gt;// query the database if the user is authorized&lt;br /&gt;$username = "administrator";&lt;br /&gt;$password = sha1("password");&lt;br /&gt;if (!$dbq-&amp;gt;{"SELECT * FROM admin_user WHERE username=? " .&lt;br /&gt;    "AND password=?"}(array($username, $password))) {&lt;br /&gt;    die("Unauthorized.");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// query the database and display some records&lt;br /&gt;$dbq-&amp;gt;{"SELECT id, first_name, last_name FROM employee"};&lt;br /&gt;foreach ($dbq as $result) {&lt;br /&gt;    print_r($result);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// casting the object as a string yields the query string&lt;br /&gt;echo "Query: $dbq";&lt;br /&gt;&lt;/pre&gt;Don't try this at home, though, my friends. Just because you can write code like this doesn't mean you should.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-1831927960243825539?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/1831927960243825539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/01/database-access.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1831927960243825539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/1831927960243825539'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/01/database-access.html' title='Evil Access'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-979400130116934238</id><published>2009-01-14T23:41:00.008-05:00</published><updated>2010-01-17T18:56:28.990-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Humor'/><title type='text'>Motivational Posters</title><content type='html'>I've been having a hell of a time fighting with some Perl code at work lately.  I tossed together a humorous Perl &lt;a href="http://despair.com/"&gt;demotivational poster&lt;/a&gt; to release some of my frustration, and thought others might appreciate it.&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 320px;" src="http://www.saltcitytech.com/blogger/motivation_perl.jpg" alt="" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;But why stop there?  There are other languages worth making fun of besides Perl!  So, I tossed together some more snarky posters to be fair.&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 320px;" src="http://www.saltcitytech.com/blogger/motivation_cpp.jpg" alt="" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 320px;" src="http://www.saltcitytech.com/%7Etboronczyk/blogger/Java%20-%2003%20-%20small.jpg" alt="" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 320px;" src="http://www.saltcitytech.com/blogger/motivation_lisp.jpg" alt="" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 320px;" src="http://www.saltcitytech.com/blogger/motivation_php.jpg" alt="" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 320px;" src="http://www.saltcitytech.com/blogger/motivation_ruby.jpg" alt="" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 400px; height: 320px;" src="http://www.saltcitytech.com/blogger/motivation_vb.jpg" alt="" border="0" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-979400130116934238?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/979400130116934238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/01/motivational-posters.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/979400130116934238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/979400130116934238'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/01/motivational-posters.html' title='Motivational Posters'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8004350529751464986</id><published>2009-01-04T23:26:00.019-05:00</published><updated>2011-04-14T22:00:46.542-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>7 Things You Didn't Care to Know About Me</title><content type='html'>I've been tagged by &lt;a href="http://blog.phpdeveloper.org/?p=113"&gt;Chris Cornutt&lt;/a&gt; and &lt;a href="http://www.tetraboy.com/archives/4-7-things-you-didnt-know,-or-want-to-know,-about-me..html"&gt;Jeff Jones&lt;/a&gt; to share some things you probably don't know about me. (It's nice to see chain mails flow through the blogosphere too, eh?)  So, here's seven little-known facts about yours truly...&lt;br /&gt;&lt;ol&gt;&lt;li&gt;My first career choice was to be a diocesan priest, and I briefly attended Seminary after I graduated from high school.  My family isn't overly religious, and my parents didn't push me to go; I think I just like to help people and felt drawn to the rich history of the Roman Catholic Church.  Life has a funny way of playing out differently than we intend for it, doesn't it?&lt;/li&gt;&lt;li&gt;After I left seminary, I attended a state university and majored in elementary education with a concentration in music history and literature.  I'm not overly fond of children, though, so I didn't complete the program.  I would only need to take two more classes to be a state-certified elementary teacher.&lt;/li&gt;&lt;li&gt;I studied French for 5 years in high school, a year of Latin in the seminary, and then learned Esperanto independently.&lt;/li&gt;&lt;li&gt;Someday I'd like to run for Governor of New York, though I'm certain nobody would vote for me.  My biggest push would be to reform of the state's tax laws, though I'd probably legalize prostitution... people are going to do it anyway so the state might as well make money off it.&lt;/li&gt;&lt;li&gt;I try to make sure I have a bunch of $1 bills in my pocket when I go to parties; you never know what you can pay a drunk person to do for your own personal amusement.  I once had a guy prancing about in a blue speedo for $5.  Another time, the same guy chewed on a ball of tinfoil for 30 seconds for $1. I think that officially makes me an asshole.&lt;/li&gt;&lt;li&gt;I crawled on top of the dining room table when I was a baby, fell off, and tore the &lt;a href="http://en.wikipedia.org/wiki/Frenulum_linguae"&gt;frenulum&lt;/a&gt; under my tongue.  I didn't gain any super-human abilities with my tongue... just reduced frenula tissue.&lt;/li&gt;&lt;li&gt;I don't use shaving cream.  I would inevitably get it in an ear or up a nostril and it would bother me.  Instead, I shave in the shower after the warm water has softened my skin and use a disposable razor that has an aloe strip.&lt;/li&gt;&lt;/ol&gt;So there you have it.  I'm supposed to tag other people and have them share seven things about themselves as well, though everyone to whom I would have sent it has already participated.  Sorry... That's all, folks!&lt;br /&gt;&lt;br /&gt;If you're curious about the deep, dark secrets of others in the PHP Community, you may want to &lt;a href="http://www.phpdeveloper.org/news/11665"&gt;checkout the list&lt;/a&gt; Cornutt compiled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8004350529751464986?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8004350529751464986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/01/7-things-you-didnt-care-to-know-about.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8004350529751464986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8004350529751464986'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/01/7-things-you-didnt-care-to-know-about.html' title='7 Things You Didn&apos;t Care to Know About Me'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-9045252067424287255</id><published>2009-01-01T04:39:00.007-05:00</published><updated>2009-06-11T01:08:54.526-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>Happy New Year</title><content type='html'>I've never been one to make New Year's resolutions. If I really want to change something about myself or my life, why what until January 1st to set goals for myself?  It doesn't matter to me if it's January 1st, April 15th, July 4th, or December 26th... I just set goals and go for them!&lt;br /&gt;&lt;br /&gt;Instead, I prefer to choose an over-reaching theme for the year. This suits me better because there's no success or failure benchmarks to meet; it's something I keep in mind to help guide me as I tackle the challenges and opportunities that come my way.&lt;br /&gt;&lt;br /&gt;2006 was my "Year of Adventure."&lt;br /&gt;&lt;br /&gt;2007 was my "Year of Change."&lt;br /&gt;&lt;br /&gt;2008 was my "Year of Success."&lt;br /&gt;&lt;br /&gt;What will 2009 be? &lt;br /&gt;&lt;br /&gt;I've chosen to designate 2009 as a "Year of Balance" for myself.  Like everyone, there's good things and bad things in my life; putting the balance back into my life again will empower me to better appreciate the good and deal with the bad more productively.&lt;br /&gt;&lt;br /&gt;So, it was very fitting the other day when I saw this beautiful video featured on the &lt;a href="http://apod.nasa.gov/apod/ap081231.html"&gt;Astronomy Picture of the Day&lt;/a&gt; website.  The site's goal is to present images, videos and descriptions to inspire people to learn more about astronomy, though I found this particular video inspiring in a different way.&lt;br /&gt;&lt;br /&gt;In the short 4-minutes or so that it took to watch the video, I found myself pondering the beauty of nature that surrounds us, and how sad it is that so many of us never appreciate it because we're too busy going about our daily lives.  I then found myself thinking about what things in life are truly important, and what I should focus on as I live my life.&lt;br /&gt;&lt;br /&gt;Each day I will work and be productive, I will play and relax, I will laugh, love, and enjoy the company of friends, and I will find new things in my life deserving of my appreciation.&lt;br /&gt;&lt;br /&gt;&lt;object width="400" height="268"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=1250929&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1"&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=1250929&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="268"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Happy New Year; I wish you and all your loved ones the best in 2009.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-9045252067424287255?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/9045252067424287255/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2009/01/happy-new-years.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/9045252067424287255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/9045252067424287255'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2009/01/happy-new-years.html' title='Happy New Year'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5460249023732764049</id><published>2008-12-19T15:15:00.013-05:00</published><updated>2009-07-05T11:49:14.954-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='Paste Ninja'/><title type='text'>Paste Ninja Goes Multilingual</title><content type='html'>Chris Cornutt was nice enough to give &lt;a href="http://www.pasteninja.com/"&gt;Paste Ninja&lt;/a&gt; (the premier PHP-powered pastebin app) some exposure by highlighting it on &lt;a href="http://phpdeveloper.org/news/11525"&gt;PHPDeveloper.org&lt;/a&gt; a week or so ago.  Thanks, Chris!   As a result of the extra publicity, the site saw an increase in traffic as people came to check it out.    I hope they liked what they saw... but stay tuned, because there's more features to come!&lt;br /&gt;&lt;br /&gt;It was interesting to look through the access logs afterward.  There are a lot of pastebins available on the Internet, but the feature set and usability of the application is what will help differentiate it from the rest.  The list of countries from which various people visited and the values of their browser's Language-Accept headers peeked my interest, and I realized that I needed to offer Paste Ninja's interface in multiple languages so people could use my service in whichever language they may find the most comfortable.  So, Paste Ninja is now multilingual!&lt;br /&gt;&lt;br /&gt;The goal is to translate PasteNinja's interface into the top 10 or so languages.  I'm obviously not not going to be able to accurately translate all of the necessary text into each language myself, so I've started enlisting some help.&lt;br /&gt;&lt;br /&gt;Years ago I studied French and Esperanto, so those were the first two languages I targeted.   I then searched out people who were willing to review my work and correct any grammar deficiencies and the like.   With the help of &lt;a href="http://babelfish.yahoo.com/"&gt;Babelfish&lt;/a&gt;, &lt;a href="http://translate.google.com/"&gt;Google Translate&lt;/a&gt;, and some very creative Internet searching, I was able to produce rough translations in other languages.&lt;br /&gt;&lt;br /&gt;If you ever need a professional French translator, &lt;a href="http://www.linkedin.com/pub/0/a/a8b"&gt;Sophie Vialaneix&lt;/a&gt; is unbelievably good in every way and comes with my highest recommendation.  She was so friendly and professional that it made me wish I had more text for her to review  (thanks, Sophie)!  &lt;a href="http://www.wolerized.com/blog/remi-woler"&gt;Remi Woler&lt;/a&gt; from #phpc was wonderful and offered to correct my Dutch (thanks, Remi).  My friend and co-worker &lt;a href="http://www.mladenov.net/"&gt;Bobby Mladenov&lt;/a&gt; graciously provided a Bulgarian translation (thanks, Bobby), and Dr. Wing Ming Chan is also graciously providing a Chinese translation (thanks, Wing).  Keep their efforts in mind as well when you see text that doesn't read "Grandmother your password here."&lt;br /&gt;&lt;br /&gt;The interface is available in other languages as well, such as German, Italian, Polish, Portuguese, Russian, and Spanish.  These were produced with translation software and some creative Internet searching, so expect them to be less-than-perfect.  I will revise the translations as I find people proficient in them who are willing to review them.  If you'd like to volunteer your skills, just leave a comment and let me know!&lt;br /&gt;&lt;br /&gt;Oh, and the interface is also available in Pig Latin just for fun. I'm sure &lt;a href="http://benramsey.com/"&gt;Ben Ramsey&lt;/a&gt; will be happy to take all the credit for that idea. ;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 12/21/08: &lt;/span&gt;&lt;a href="http://blog.wombert.de/"&gt;David Zülke&lt;/a&gt; was kind enough to review the German translation. Thanks, David!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 12/23/08:&lt;/span&gt; Sacha Poznyak was kind enough to review the Russian translation, Ali Curtis was kind enough to review the Spanish translation, and David Cole was kind enough to review the Portuguese. Thanks, Sacha, Ali and David!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 12/31/08: &lt;/span&gt;&lt;a href="http://www.limeexchange.com/search/provider/6538"&gt;Shahar Fisher&lt;/a&gt; was gracious enough to donate his time to review the Hebrew translation. Thank you, Shahar!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5460249023732764049?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5460249023732764049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2008/12/paste-ninja-goes-multilingual.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5460249023732764049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5460249023732764049'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2008/12/paste-ninja-goes-multilingual.html' title='Paste Ninja Goes Multilingual'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-8114798057381293504</id><published>2008-12-12T15:19:00.006-05:00</published><updated>2011-06-04T18:26:49.829-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Perl'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='General Programming'/><title type='text'>PHP != Perl</title><content type='html'>People irk me when they expect PHP to behave like &amp;lt;insert your favorite language here&amp;gt;.  Most recently, I ran across this blog entry &lt;a href="http://mamchenkov.net/wordpress/2008/12/12/perl-vs-php-variable-scoping/"&gt;Perl vs PHP: Variable Scoping&lt;/a&gt; via the help of &lt;a href="http://www.phpdeveloper.org/"&gt;PHPDeveloper.org&lt;/a&gt;.  I'm sure Leonid is a great fellow and really smart... but he just happened to trip my irk-wire.&lt;br /&gt;&lt;br /&gt;The post is an innocent enough "here's a problem that I ran into, so I'll blog it in case someone else has the same issue."  Reading between the lines though, I get the feeling his underlying belief is that because PHP and Perl are similar that they should have the same variable scoping rules, and that since PHP's doesn't correspond to Perl's that PHP is wrong and this should be documented as such.&lt;br /&gt;&lt;br /&gt;Each language is different.  If PHP were so similar to Perl, it wouldn't be called PHP... it'd be called Perl.  Or maybe a dialect, like PHPerl.  I really wish people would stop comparing the two.  Quite frankly, I don't see much similarity between the two languages at all.&lt;br /&gt;&lt;br /&gt;Maybe I can get away with saying PHP and Lisp are similar because I can do the same thing in both languages!&lt;br /&gt;&lt;pre&gt;$a = 2 + 2 * 4;&lt;br /&gt;echo $a;&lt;br /&gt;&lt;br /&gt;(setq a (* (+ 2 2) 4))&lt;br /&gt;a&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Update 12/20/2008:&lt;/b&gt; Luke Wellington wrote a brief article entitled &lt;a href="http://phpadvent.org/2008/php-is-not-java-by-luke-welling"&gt;PHP Is Not Java&lt;/a&gt; for the PHP Advent 2008 project. I'm glad to see I'm not the only one who gets irked by such things (though he is much more eloquent about it than I am).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-8114798057381293504?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/8114798057381293504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2008/12/php-perl.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8114798057381293504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/8114798057381293504'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2008/12/php-perl.html' title='PHP != Perl'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-3088857994413644383</id><published>2008-12-07T23:25:00.006-05:00</published><updated>2010-01-17T18:53:41.936-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Projects'/><title type='text'>JavaScript Keyboard Widget</title><content type='html'>&lt;div&gt;Have you ever done something stupid just so you don't have to do whatever it is you're supposed to be doing because you feel like procrastinating?  I found myself doing that this evening by programming a keyboard widget in JavaScript.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Right now it's just sloppy code without any real functionality, but feel free to take a look at it at  &lt;a href="http://www.saltcitytech.com/projects/keyboard"&gt;http://www.saltcitytech.com/projects/keyboard&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Theoretically, one could add a couple of state variables to monitor the ctrl, shift, alt and caps lock keys, check those variables in the keys' onclick callback, and have a fully functional keyboard widget.  Since the key characters are defined in a mapping object, it should be relatively easy to internationalize it just by changing the mapping definitions.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;I may clean up the code in the future depending if someone actually sees a viable use for it or if I find myself needing to procrastinate again.&lt;/div&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; width: 295px; height: 131px;" src="http://saltcitytech.com/blogger/keyboard.png" alt="" border="0" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-3088857994413644383?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/3088857994413644383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2008/12/javascript-keyboard-widget.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3088857994413644383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/3088857994413644383'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2008/12/javascript-keyboard-widget.html' title='JavaScript Keyboard Widget'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5744344919271117389</id><published>2008-12-04T21:31:00.011-05:00</published><updated>2011-06-30T14:07:05.801-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Projects'/><category scheme='http://www.blogger.com/atom/ns#' term='Paste Ninja'/><title type='text'>Dialog and Paste Ninja</title><content type='html'>I'd like to share with everyone two projects that I've been working on in what little spare time I've had lately-- Dialog and Paste Ninja.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dialog&lt;/b&gt;&lt;br /&gt;Dialog is a lightweight JavaScript-based dialog window. Why does the world need another dialog widget, you ask? It probably doesn't, but I couldn't find a freely available one that was as flexible as I wanted so I wrote my own. Flexibility and portability were key design features, so Dialog is written completely in JavaScript and CSS, and its appearance is fully CSS driven.&lt;br /&gt;&lt;br /&gt;Dialog supports multiple dialog types by default, such as confirmation, information, warning, and error, and can further be customized with a custom dialog type. It can even display modal dialogs and block input to the page until the prompt is dismissed!&lt;br /&gt;&lt;br /&gt;You can learn more about it and get the code &lt;s&gt;at its project page, &lt;a href="http://www.saltcitytech.com/projects/dialog/"&gt;http://www.saltcitytech.com/projects/dialog&lt;/a&gt;&lt;/s&gt; from my &lt;a href="https://github.com/tboronczyk/JavaScript-Experiments"&gt;JavaScript Experiments repository&lt;/a&gt; at GitHub.&lt;br /&gt;&lt;br /&gt;&lt;img alt="" border="0" src="http://www.saltcitytech.com/blogger/dialog.jpg" style="display: block; height: 128px; margin: 0px auto 10px; text-align: center; width: 402px;" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Paste Ninja&lt;/b&gt;&lt;br /&gt;Paste Ninja is a pastebin application that lets you to share code snippets with others. Instead of flooding an IRC channel or your Instant Messenger conversations with lines of source code, you can paste it online for public viewing.&lt;br /&gt;&lt;br /&gt;The world probably doesn't need another pastebin app, either, but there are several features in store that other pastebins don't have. The goal is to revolutionize how people use pastebins and make internet debugging a truly collaborative experience.&lt;br /&gt;&lt;br /&gt;The back-end of Paste Ninja is written in PHP and uses a MySQL database to store pastes, comments, and the application's configuration information. The front-end is written in JavaScript.&lt;br /&gt;&lt;br /&gt;I haven't decided yet if I'm going to opensource the code for Paste Ninja-- or under which license it would be released under if I did so-- but I'm not adverse to the idea if there is enough demand. Regardless, it's free to use, so be the "master of your pastebin" and give Paste Ninja a try at &lt;a href="http://www.pasteninja.com/"&gt;http://www.pasteninja.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;img alt="" border="0" src="http://www.saltcitytech.com/blogger/pasteninja.com.jpg" style="display: block; height: 324px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5744344919271117389?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5744344919271117389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2008/12/dialog-and-paste-ninja.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5744344919271117389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5744344919271117389'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2008/12/dialog-and-paste-ninja.html' title='Dialog and Paste Ninja'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-6276979862547260191</id><published>2008-11-28T21:21:00.005-05:00</published><updated>2011-06-30T13:09:44.400-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Language Design'/><title type='text'>Choosing an Assignment Operator</title><content type='html'>If you were to write your own programming language (as I still intend to do someday even if only for the learning experience it provides me), what symbol (or symbols) would you use to represent the assignment operator?&lt;br /&gt;&lt;br /&gt;Even though it would looks like BNF or old-school Pascal, I would lean towards using &lt;tt&gt;:=&lt;/tt&gt; as the assignment operator.  That would leave me free to use &lt;tt&gt;=&lt;/tt&gt; for equality and there wouldn't be the issue of &lt;tt&gt;=&lt;/tt&gt; vs. &lt;tt&gt;==&lt;/tt&gt; tripping up new programmers.  Besides, performing assignments is more common than making comparisons, so perhaps assignment should have the more distinct operator.  Going one step further, if the language I wrote was not strongly typed, I would use &lt;tt&gt;==&lt;/tt&gt; as the identity operator (as like PHP's &lt;tt&gt;===&lt;/tt&gt;).  &lt;tt&gt;:=&lt;/tt&gt; and &lt;tt&gt;=&lt;/tt&gt; to &lt;tt&gt;==&lt;/tt&gt; seems a more logical progression to me than &lt;tt&gt;=&lt;/tt&gt; and &lt;tt&gt;==&lt;/tt&gt; to &lt;tt&gt;===&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;I suspect I wouldn't use &lt;tt&gt;=&lt;/tt&gt; as both assignment and comparison as Basic does because of the ambiguity it causes.  For example:&lt;br /&gt;&lt;pre&gt;x = y = 0&lt;/pre&gt;Does this mean "assign 0 to both &lt;tt&gt;x&lt;/tt&gt; and &lt;tt&gt;y&lt;/tt&gt;", or "assign the boolean comparison whether the value of &lt;tt&gt;y&lt;/tt&gt; is 0 to x?"  Statements such as these:&lt;br /&gt;&lt;pre&gt;x := y = 0&lt;br /&gt;x := y := 0&lt;/pre&gt;are then both clear in their meaning.&lt;br /&gt;&lt;br /&gt;I think my second choice would be just &lt;tt&gt;:&lt;/tt&gt; and have something like:&lt;br /&gt;&lt;pre&gt;x: 2 + 2&lt;/pre&gt;The lvalue appears as if it were a label, giving the visual representation that &lt;tt&gt;x&lt;/tt&gt; means &lt;tt&gt;2 + 2&lt;/tt&gt;. Plus, it would be one (of many) syntaxtic differences that would separate my language from the others.  I don't know of any languages that currently use &lt;tt&gt;:&lt;/tt&gt; as an assignment operator.&lt;br /&gt;&lt;br /&gt;Of course, this all presumes the elements of a statement are written in a certain order.  If you were to use a keyword such as &lt;tt&gt;set&lt;/tt&gt;:&lt;br /&gt;&lt;pre&gt;x set 2 + 2&lt;/pre&gt;just appears awkward to me.  It would have to be:&lt;br /&gt;&lt;pre&gt;set x 2 + 2&lt;/pre&gt;But if you always require the assignment target on the left-hand side of your operator, then is an explicit assignment operator really required as all?  The implied assignment operation of something like:&lt;br /&gt;&lt;pre&gt;x 2 + 2&lt;/pre&gt;is clean and succinct.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-6276979862547260191?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/6276979862547260191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2008/11/choosing-assignment-operator.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6276979862547260191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/6276979862547260191'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2008/11/choosing-assignment-operator.html' title='Choosing an Assignment Operator'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3224008808345429390.post-5574974834039718601</id><published>2008-11-10T12:51:00.012-05:00</published><updated>2011-06-30T14:03:00.048-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>JavaScript Frameworks Suck</title><content type='html'>There's been an interesting discussion off and on around the office this past couple of weeks about JavaScript frameworks, specifically which framework is the best so we can standardize on one. Of course I have to be difficult... my answer is none of them.&lt;br /&gt;&lt;br /&gt;As a general rule of thumb, "frameworks are evil." There are exceptions, but frameworks seem to cause a lot of unnecessary bloat, make tasks difficult to accomplish if they fall outside the intended scope of the framework, create obstacles to efficient debugging, and adversely affect page load times causing the application to appear slow and sluggish. The real question ought not be what framework is best, but rather be what exactly are you trying to accomplish with client-side scripting in the first place.&lt;br /&gt;&lt;br /&gt;Creating a rich user experience with standard JavaScript is not difficult. Many of the niceties the frameworks provide aren't magic... for example, &lt;tt&gt;$()&lt;/tt&gt; is just &lt;tt&gt;function(x) document.getElementById(x);}&lt;/tt&gt;. And AJAX is easy if you forgo XML in favor of JSON as your transfer format. If you don't understand your goals then you might as well just shoot yourself in the foot.&lt;br /&gt;&lt;br /&gt;Once you have identified exactly what your needs are, and &lt;i&gt;if&lt;/i&gt; those needs suggest you use a framework, then those needs will also dictate which framework would be suitable for use. If you need widgets, for example, then YUI! would stand out more as the best choice. If you need modularity and flexibility instead, then MooTools might be the way to go.&lt;br /&gt;&lt;br /&gt;To further illustrate my point to a coworker that frameworks don't always make things easier, I implemented a basic Accordion widget in MooTools and straight-up plain old JavaScript. The development time in JavaScript proper was half-that of developing with MooTools because I didn't have to learn any special APIs, scrounge the documentation for a list of dependency files, etc. My implementation weighs in at 50 lines vs. MooTools' 3,100+ lines and 21 dependency files.&lt;br /&gt;&lt;pre&gt;function $$(className) {&lt;br /&gt;    var classElements = new Array();&lt;br /&gt;    var els = document.getElementsByTagName("*");&lt;br /&gt;    var pattern = new RegExp('(^|\\s)' + className + '(\\s|$)');&lt;br /&gt;&lt;br /&gt;    for (var i = 0, j = 0; i &amp;lt; els.length; i++) {&lt;br /&gt;        if (pattern.test(els[i].className)) {&lt;br /&gt;            classElements[j] = els[i];&lt;br /&gt;            j++;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return classElements;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function Accordion(headerClass, panelClass, showIndex) {&lt;br /&gt;    this.headers = $$(headerClass);&lt;br /&gt;    this.panels  = $$(panelClass);&lt;br /&gt;&lt;br /&gt;    for (var i = 0; i &amp;lt; this.headers.length; i++) {&lt;br /&gt;        this.headers[i].args = {&lt;br /&gt;            index: i,&lt;br /&gt;            headers: this.headers,&lt;br /&gt;            panels : this.panels&lt;br /&gt;        };&lt;br /&gt;        this.headers[i].onclick = function () {&lt;br /&gt;            var a = this.args;&lt;br /&gt;            for (var i = 0; i &amp;lt; a.panels.length; i++) {&lt;br /&gt;                a.panels[i].style.display = ( i == a.index) ?&lt;br /&gt;                    "" : "none";&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    (showIndex === undefined ? this.headers[0] : &lt;br /&gt;        this.headers[showIndex]).onclick();&lt;br /&gt;&lt;br /&gt;    return true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;window.onload = function() {&lt;br /&gt;    new Accordion("a_header", "a_body");&lt;br /&gt;};&lt;/pre&gt;Sure it's not as "feature rich" as MooTools' Accordion, but any additional features can easily be added when the time comes, and they certainly wouldn't require 3,050 more lines of code.&lt;br /&gt;&lt;br /&gt;People want fast front-ends. They're impatient and don't want to wait. Bloated code slows down the front-end and gives them impression of a slow back-end. Half the development time and 98.4% less code? Now that sounds good to me!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3224008808345429390-5574974834039718601?l=zaemis.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zaemis.blogspot.com/feeds/5574974834039718601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://zaemis.blogspot.com/2008/11/theres-been-interesting-discussion-off.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5574974834039718601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3224008808345429390/posts/default/5574974834039718601'/><link rel='alternate' type='text/html' href='http://zaemis.blogspot.com/2008/11/theres-been-interesting-discussion-off.html' title='JavaScript Frameworks Suck'/><author><name>Timothy Boronczyk</name><uri>http://www.blogger.com/profile/00015151416507514182</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-q80DeldNH3E/TnldVChVOkI/AAAAAAAAAXQ/TieqIhd51GI/s220/317069_10150361056106369_744706368_9727506_5677056_n.jpg'/></author><thr:total>1</thr:total></entry></feed>
