<?xml version="1.0" encoding="UTF-8"?>

<rss version='2.0' 
     xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"
     xmlns:doap="http://usefulinc.com/ns/doap#"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

    <channel>
        <!-- This XML Feed shows details for the page User:marc 
             and everything recently tagged User:marc -->
        <creativeCommons:license>http://creativecommons.org/licenses/by-sa/2.5/
          </creativeCommons:license>
        <title>User:marc on SWiK</title>
        <doap:name>User:marc</doap:name>
        <doap:description>&lt;p&gt;Hello!  My name is &lt;strong&gt;Marc Wandschneider&lt;/strong&gt;.  I am one of the lead developers on &lt;a class="wikilink" href="http://swik.net/SWiK"&gt;SWiK&lt;/a&gt; and author of &lt;a rel="nofollow" href="http://www.phptr.com/title/0131867164"&gt;Core Web Application Programming with &lt;span class="caps"&gt;PHP&lt;/span&gt; and MySQL&lt;/a&gt;, published by Prentice-Hall.&lt;/p&gt;


	&lt;p&gt;My technical/personal blog is at &lt;a rel="nofollow" href="http://www.chipmunkninja.com"&gt;www.chipmunkninja.com&lt;/a&gt;.  My travel blogs are at &lt;a rel="nofollow" href="http://travel.lanfear.com"&gt;http://travel.lanfear.com&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;I have been a programmer for well over 15 years, starting out accidentally after spending waaay too much time on a friend&amp;#8217;s computer at University.&lt;/p&gt;


	&lt;p&gt;My key interests in computing have always been in development tools and user interface design and programming.  A high quality rapid application development environment with a powerful language, easy to use environment, and a portable (read: small) and fast runtime is a rare thing indeed.  Tools such as Visual Basic v1-3 and Borland&amp;#8217;s &lt;a class="wikilink" href="http://swik.net/Delphi"&gt;Delphi&lt;/a&gt; tool are a dying breed.&lt;/p&gt;


	&lt;p&gt;In the user interface arena, I am constantly saddened by the amount of time and energy people put into making their applications gratuitously different and thus frustrating for the end user to figure out.  Recent operating systems such as Apple&amp;#8217;s  &lt;a class="wikilink" href="http://swik.net/OS-X"&gt;&lt;span class="caps"&gt;OS X&lt;/span&gt;&lt;/a&gt; have made some improvement in enforcing user interface restrictions, but even these are likely susceptible to the inevitable decline seen in popular consumer operating systems such as Windows.&lt;/p&gt;


	&lt;p&gt;I have recently spent much of my time working with web applications and am interested in how they, especially using all the new rounded corners in &lt;a class="wikilink" href="http://swik.net/Web-2.0"&gt;Web 2.0&lt;/a&gt;, will affect the way in which traditional web applications are developed.  I balance my efforts between design, performance, scalability, and maintainability.&lt;/p&gt;


	&lt;p&gt;Some of the major things I have done in my professional career include:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Working for Microsoft for nearly 6 years in the 1990s, working on such things as &lt;a class="wikilink" href="http://swik.net/Visual-Basic"&gt;Visual Basic&lt;/a&gt;, Visual J++, and &lt;span class="caps"&gt;WFC&lt;/span&gt;.  One of the most fun things I did during this time was releases the MarcWan / BaseCtl framework for writing fast, high performance &lt;a class="wikilink" href="http://swik.net/ActiveX"&gt;ActiveX&lt;/a&gt; Controls (minimum ctl was about 12k, with one page loaded in memory).&lt;/li&gt;
		&lt;li&gt;Wrote &lt;a rel="nofollow" href="http://kiltdown.sourceforge.net"&gt;Kiltdown&lt;/a&gt;, an Outlook Express Clone for non-Windows platforms written in &lt;a class="wikilink" href="http://swik.net/Qt"&gt;Qt&lt;/a&gt;.&lt;/li&gt;
		&lt;li&gt;Written some persistence code for the &lt;a class="wikilink" href="http://swik.net/TabletPC"&gt;TabletPC&lt;/a&gt; inking engine.&lt;/li&gt;
		&lt;li&gt;Designed and implemented &lt;a class="wikilink" href="http://swik.net/Swik"&gt;Swik&lt;/a&gt;.&lt;/li&gt;
		&lt;li&gt;Written a &lt;a class="wikilink" href="http://swik.net/PHP"&gt;&lt;span class="caps"&gt;PHP&lt;/span&gt;&lt;/a&gt; and &lt;a class="wikilink" href="http://swik.net/MySQL"&gt;MySQL&lt;/a&gt; &lt;a class="wikilink" href="http://swik.net/Web-Application"&gt;Web Application&lt;/a&gt; Programming Book.&lt;/li&gt;
		&lt;li&gt;My current project is an image viewing program for Mac &lt;span class="caps"&gt;OS X&lt;/span&gt; called &lt;a rel="nofollow" href="http://chipmunkninja.com/justlooking2"&gt;JustLooking&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;I now divide my time between learning spoken languages and spending far too much time in front of my Powerbook.  I currenty live in Beijing, China.&lt;/p&gt;
</doap:description>
        <description>Hello!  My name is Marc Wandschneider.  I am one of the lead developers on SWiK and author of Core Web Application Programming with PHP and MySQL, published by Prentice-Hall.


	My technical/personal blog is at www.chipmunkninja.com.  My travel blogs are at http://travel.lanfear.com


	I have been a programmer for well over 15 years, starting out accidentally after spending waaay too much time on a friend&amp;#8217;s computer at University.


	My key interests in computing have always been in develo</description> 
	  <!-- see doap:description for full description -->
        <link>http://swik.net/User:marc</link>
        <doap:homepage></doap:homepage>
                <category>user:marc</category>
        <category>PHP</category>
        <category>MySQL</category>
        <category>osx</category>
        <category>marc</category>
        <category>wandschneider</category>

        <pubDate>Thu, 29 Sep 2005 17:23:03 -0700</pubDate>
        <lastBuildDate>Mon, 12 Mar 2007 04:53:00 -0700</lastBuildDate>
            
        <item>
            <title>PHP QuÃ©bec talks</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/PHP+Qu%C3%83%C2%A9bec+talks/b3mc4</link>
            <description>&lt;div style=&quot;float: right; margin: 0.5em&quot;&gt;
&lt;a href=&quot;http://conf.phpquebec.com&quot;&gt;&lt;img src=&quot;http://conf.phpquebec.com/img/icone/2008/conf_phpquebec_en.gif&quot; border=&quot;0&quot;/&gt;&lt;/a&gt;&lt;/div&gt;

	&lt;p&gt;This year, as part of my annual trip to Canada and the &lt;span class=&quot;caps&quot;&gt;USA&lt;/span&gt;, I&amp;#8217;ve been asked to give two talks at the annual &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; Québec conference in Montréal.  I haven&amp;#8217;t been back to that city since 1993 when I graduated from University, and it will be interesting to see how it goes.  (Although I suspect that while Beijing basks in nearly 20C (nearly 70F)  weather every day and even Seattle and New York were closer to 10C (50F), Montréal is still hanging below freezing most days and has over a metre of snow on the ground).&lt;/p&gt;


	&lt;p&gt;I will be giving talks on internationalisation (commonly just called i18n) and giving your database servers a break with memcached.  If you&amp;#8217;re anywhere in the neighbourhood, come on by for some good fun.  I&amp;#8217;ll be getting back to regular programming content this weekend.&lt;/p&gt;


	&lt;p&gt;The slides for my presentations are here:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://chipmunkninja.com/article/phpquebec-memcached&quot;&gt;memcached&lt;/a&gt; (FIXED)&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://chipmunkninja.com/article/phpquebec-i18n&quot;&gt;i18n&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;[Sorry for the delay in fixing the memcached link &amp;#8211; I have had a severe flu for the last few days.  It should be okay now.]&lt;/p&gt;</description>
            
            <pubDate>Wed, 12 Mar 2008 10:43:31 -0700</pubDate>
        </item>
            
        <item>
            <title>Fifteen years in the making - Nethack Ascension Report</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Fifteen+years+in+the+making+-+Nethack+Ascension+Report/bzzew</link>
            <description>&lt;p&gt;&lt;img style=&quot;float: right; margin: 1em&quot; border=&quot;0&quot; src=&quot;http://chipmunkninja.com/images/nh.png&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;This is a bit of a geeky post, but then this is a geeky computer blog, so &amp;#8230; so be it.   Regular readers of this blog will know that I&amp;#8217;m a fan of &lt;a href=&quot;/article/nethack&quot;&gt;Nethack&lt;/a&gt;, and have been playing it on and off for over fifteen years (mostly off, but recently I&amp;#8217;ve rediscovered it again).  Well, finally, after all this time, I can say the following:&lt;/p&gt;


&lt;pre&gt;

Goodbye marcw the Demigod...

You went to your reward with 5941448 points,
The Book of the Dead (worth 10000 zorkmids and 25000 points)
Vorpal Blade (worth 4000 zorkmids and 10000 points)
The Heart of Ahriman (worth 2500 zorkmids and 6250 points)
The Bell of Opening (worth 5000 zorkmids and 12500 points)
The Candelabrum of Invocation (worth 5000 zorkmids and 12500 points)
       8 emeralds (worth 20000 zorkmids),
       2 diamonds (worth 8000 zorkmids),
       2 rubies (worth 7000 zorkmids),
       1 amulet of ESP (worth 150 zorkmids),
       1 amulet of unchanging (worth 150 zorkmids),
and 2497 pieces of gold, after 93897 moves.
You were level 22 with a maximum of 95 hit points when you ascended.

 No  Points     Name                                                   Hp [max]
  1    5941448  marcw-Bar-Hum-Mal-Neu ascended to demigod-hood.        95  [95]
  2    2623722  marcw-Val-Hum-Fem-Neu died on the Plane of Fire.
                Dissolved in molten lava (with the Amulet).           129 [287]
  3    1330849  marcw-Val-Hum-Fem-Neu choked on her food in Gehennom
                on level 33.  Choked on a disenchanter corpse.        248 [248]

&lt;/pre&gt;

	&lt;p&gt;Interestingly, I almost always play Valkyries, but decided to try Barbarians for a couple of games.  The first game, I made it all the way down to level 24 without finding a single altar (except for a non-aligned one in the mines with a nasty priest next to it) before an Arch-Lich and Titan finished me off.   The second game was this one. Most of the rest of the time, I do embarrassing things like choke on things or eat something I shouldn&amp;#8217;t have.  Need to be more careful, I suppose.&lt;/p&gt;


	&lt;p&gt;Well, that&amp;#8217;s all there is to this post, but it&amp;#8217;s exciting news for me.  I&amp;#8217;m still playing, and now trying other classes (read:  dying a lot).&lt;/p&gt;</description>
            
            <pubDate>Tue, 08 Jan 2008 22:16:32 -0800</pubDate>
        </item>
            
        <item>
            <title>End of an Era</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/End+of+an+Era/be1yf</link>
            <description>&lt;p&gt;For the last 17 years or so, I&amp;#8217;ve been a huge fan of the various &lt;span class=&quot;caps&quot;&gt;BSD&lt;/span&gt;-inspired operating systems, starting with SunOS 4.1.x, and then moving on towards the various free flavours available for the PC, such as Bill Jolitz&amp;#8217;s 386bsd, then FreeBSD, NetBSD, and OpenBSD.  For a while, even I was a regular contributer to the NetBSD community, and enjoyed playing with them all.&lt;/p&gt;


	&lt;p&gt;When I started installing and running my own servers for mail and web application purposes about 8 years ago, there was an abortive few-month attempt to use Microsoft Windows Server, but since then it&amp;#8217;s all been FreeBSD, with the latest lanfear.com server being FreeBSD 4.9-RELEASE (and with an uptime of 2 years, which would have been nearly 3 had my &lt;span class=&quot;caps&quot;&gt;ISP&lt;/span&gt; not hacked and rebooted my machine one day).&lt;/p&gt;


	&lt;p&gt;To this date, various &lt;span class=&quot;caps&quot;&gt;SYSV&lt;/span&gt;-inspired features, such as &lt;em&gt;initd&lt;/em&gt; and their directory structure leave me with a bad taste in my mouth.  I have repeatedly stuck with types of linux such as SuSE (before it sucked), and Ubuntu, that still gave me &lt;code&gt;/etc/rc&lt;/code&gt; and familiar directory structures.  Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; still gives me &lt;a href=&quot;http://chipmunkninja.com/article/findthelove&quot;&gt;warm tingly feelings&lt;/a&gt; to this day.&lt;/p&gt;


	&lt;p&gt;So, it is with some sadness that I recently decided to move from my own dedicated server to a virtual server hosting solution.  I&amp;#8217;m simply never in the &lt;span class=&quot;caps&quot;&gt;USA&lt;/span&gt; any more, and I don&amp;#8217;t want to have to worry about my computer going down.  A virtual server comes with a guarantee that all hardware problems are the ISPs, and is a bit cheaper to boot.  I usually hover around a 0.00 load average, so serious computing power isn&amp;#8217;t a necessity for me.&lt;/p&gt;


	&lt;p&gt;However, the cheapest package with the best bandwidth means my server will, henceforth, be running Ubuntu Server.  It is reasonably familiar to me &amp;#8230; I can still add things to &lt;code&gt;/etc/rc.local&lt;/code&gt;, and the rest of &lt;code&gt;/etc&lt;/code&gt; isn&amp;#8217;t too alien, and the &lt;em&gt;apt-get&lt;/em&gt; scheme seems to work reasonably well.  My needs are less these days, as I slowly admit defeat in the email world and let people like Google do it for me, so as long as I can run web apps and a few other fun things, I&amp;#8217;m happy.  All of my sites and addresses have already been moved to the new server.&lt;/p&gt;


	&lt;p&gt;The old FreeBSD 1U Dell server will be shut down by the old &lt;span class=&quot;caps&quot;&gt;ISP&lt;/span&gt; on Thursday, and put in a box for a friend to go pick up sometime after that.  I&amp;#8217;ll miss it.&lt;/p&gt;</description>
            
            <pubDate>Wed, 18 Jul 2007 18:35:00 -0700</pubDate>
        </item>
            
        <item>
            <title>Things I&#039;ve learned about CoreImage (and Quartz, and OpenGL) in two weeks</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Things+I%27ve+learned+about+CoreImage+%28and+Quartz%2C+and+OpenGL%29+in+two+weeks/bdgvg</link>
            <description>&lt;p&gt;&lt;img style=&quot;float: right&quot; border=&quot;0&quot; src=&quot;http://chipmunkninja.com/images/xcodeib.png&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;I recently spent two weeks converting JustLooking, my Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; Image Viewing program, from NSImage to CoreImage and friends.  This experience was overall much easier than I expected, and I have learned a bunch of things, some of which might have been handy to have known in advance.&lt;/p&gt;


	&lt;p&gt;The good news is that it mostly lives up to the hype.  The bad news is that it&amp;#8217;s not without tricks and traps of its own.  Here are some notes and comments.&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Once set up, properly configured, coded, and tuned, CoreImage rocks.  Whereas before 10fps NSImage transitions between medium images dragged on an Intel Mac, 30fps transitions on 1GHz G4s are smooth like butter.&lt;/li&gt;
		&lt;li&gt;Proper configuration is a must.  I first just converted my various NSImage calls to their CoreImage counterparts (AppKit makes it easy to put CoreImage into your program), and saw maybe a 10-15% performance improvement.&lt;/li&gt;
		&lt;li&gt;Using CoreImage pretty much &lt;em&gt;requires&lt;/em&gt; you to start getting comfy with OpenGL and its usage in Mac Applications.   Instead of NSView classes, you need to use NSOpenGLView.  Going to do drawing in the view along with your CoreImage?  You&amp;#8217;re going to need to learn how to do this in OpenGL (or, if you&amp;#8217;re like me, find some samples that do the same thing you&amp;#8217;re doing and template heavily).&lt;/li&gt;
		&lt;li&gt;This one took me the longest time to figure out:  In Interface Builder, if your window has a subclassed NSView called MyNSView, simply changing MyNSView&amp;#8217;s superclass to be NSOpenGLView instead of NSView and changing your code files likewise is &lt;em&gt;not&lt;/em&gt; enough.  My views were drawing all sorts of weird crap all over the place and it was driving me crazy.  The part I was missing?  You have to go back to IB
	&lt;ul&gt;
	&lt;li&gt;Delete your NSView from the window.&lt;/li&gt;
		&lt;li&gt;Drag on a &lt;em&gt;new&lt;/em&gt; NSOpenGLView&lt;/li&gt;
		&lt;li&gt;And finally  mark its subclas as being MyNSView (which now inherits from NSOpenGLView instead of NSView).&lt;/li&gt;
	&lt;/ul&gt;
	&lt;/li&gt;
		&lt;li&gt;NSOpenGLView is quirky.  The weirdest of them all:  It often doesn&amp;#8217;t call your &lt;code&gt;drawRect:&lt;/code&gt; when you first display it or tell it to change its contents.  Thus, it seems as though a lot of people (myself included) have developed code that sets up a single-fire timer for some short period of time (0.1 seconds or so) to cause a redraw, which is respected.&lt;/li&gt;
		&lt;li&gt;I still cannot get an NSOpenGLView to be semi-transparent.  It&amp;#8217;s trivial to do this with an NSView&amp;#8212;just call &lt;code&gt;[[NSColor colorWithDeviceRed: 0 green: 0 blue: 0 alpha: 0.7] set]&lt;/code&gt;.  In some situations, overriding &lt;code&gt;- (BOOL)isOpaque&lt;/code&gt; might be required so you can return &lt;code&gt;NO&lt;/code&gt;.  Doing this in the NSOpenGLView, however, is a monumental effort, and something I have to figure out.  I found a few examples on the Internet, but was never able to make one work. (If you have done this before, please please please send me mail or add a comment).&lt;/li&gt;
		&lt;li&gt;Any given CIImage instance you have is probably not an actual image.  Instead, it&amp;#8217;s a collection of instructions that the CoreImage code will later use to figure out the best way to render your final image to the screen, using all sorts of cool and clever optimisations.  Applying resizing, scaling, and rotating transformations are all done at once, as none are actually computed until rendering time.&lt;/li&gt;
		&lt;li&gt;The filters you can use with CoreImage images are just awesome.  From the banal like regular NSAffineTransforms, to impressive scaling filters, to all sorts of colour and distorting filters, you might be forgiven for thinking you could write you own little Photoshop clone in a few hours.  The CILanczosScaleTransform filter, in particular, provides excellent results (sadly, it isn&amp;#8217;t quite fast enough to use in real time).&lt;/li&gt;
		&lt;li&gt;The transitions available in CoreImage are all quite cool, and reasonably easy to use.  Most simply require the setting of a few params and you&amp;#8217;re good to go&amp;#8212;one or two might require a mask image.  The one thing the docs do &lt;em&gt;not&lt;/em&gt; explain very well, however, is how to use the transitions.  Oh sure, there&amp;#8217;s a full page in the Programmer&amp;#8217;s Guide, but it blithely leaves out a few of the key steps, leaving you scratching your head.  Which brings me to my next point:&lt;/li&gt;
		&lt;li&gt;If you&amp;#8217;re going to use a CoreImage transition, download and learn to love the CITransitionSelectorSample2 sample.  Until you start playing with CoreImage (or have read this article), you might not have noticed that it uses an NSOpenGLView, that it fires a timer to make sure that NSOpenGLView always paints correctly, and more.   And It shows very clearly how to use all of pre-canned transitions in Tiger.&lt;/li&gt;
		&lt;li&gt;The CoreImage classes are not without quirks, possibly bugs (although I&amp;#8217;m such a newbie at this that I&amp;#8217;m still willing to believe they were faults of my own).  In my program I simultaneously do things like rotations, translations (so that images remain centred in the window), and scales to draw images on the screen.  On a few occasions, I found that CoreImage would draw the images correctly for a few frames in a transition, and then suddenly start drawing them in unexpected places. Only by eliminating one of the transforms was I able to eliminate these problems.&lt;/li&gt;
		&lt;li&gt;The CIImage method &lt;code&gt;imageWithContentsOfURL:&lt;/code&gt; is extremely useful for quickly loading in images, but won&amp;#8217;t let you get at things like &lt;span class=&quot;caps&quot;&gt;EXIF&lt;/span&gt; or other image meta-data.  You&amp;#8217;re far better off using CGImageSourceRef APIs to load in CGImages, and then pass these to the CIImage method &lt;code&gt;imageWithCGImage:&lt;/code&gt;.  These will even let you load in all the frames in an animated &lt;span class=&quot;caps&quot;&gt;GIF&lt;/span&gt; (something which NSImage simply does not).&lt;/li&gt;
		&lt;li&gt;For thoses cases where you &lt;em&gt;do&lt;/em&gt; want to use an NSView, such as printing, you&amp;#8217;re still more than welcome to use CIImage objects.  JustLooking does its printing in a regular NSView, and just uses AppKit extensions to the CIImage class to do the drawing.  Extremely convenient!&lt;/li&gt;
		&lt;li&gt;This isn&amp;#8217;t so much a CoreImage observation as much as an artifact of design changes I made in order to best use CoreImage:  Drawing text in an NSOpenGLView is a monstrous pain in the butt.  There are various classes and tutorials on how to do this, which is quite disheartening.  I avoided tackling this issue and got around this by just using other NSViews.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;In summary, I&amp;#8217;m extremely glad I took the CoreImage leap.  The system is extremely cool, and has pushed NSImage to a minor utility role in my programming world.  If you do decide to go for it, take heart&amp;#8212;it&amp;#8217;s really not so bad, and internet searches will give you all the help you could want.&lt;/p&gt;</description>
            
            <pubDate>Sun, 08 Jul 2007 19:57:11 -0700</pubDate>
        </item>
            
        <item>
            <title>Website Design Gone Horribly, Horribly Wrong</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Website+Design+Gone+Horribly%2C+Horribly+Wrong/99cd</link>
            <description>&lt;p&gt;&lt;img style=&quot;float: right&quot; border=&quot;0&quot; src=&quot;http://chipmunkninja.com/images/china_flag_large.png&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;There are lots of ways in which a website can be annoying.  Favourite methods include: rotating and blinking animated GIFs (or worse, Flash), popup advertising windows, unexpected background music files, or just plain all around atrociously ugly page design. (I&amp;#8217;ve been quite guilty of this in the past!)&lt;/p&gt;


	&lt;p&gt;But until you&amp;#8217;ve lived in China, or at least spent some time browsing around websites here on the mainland, there&amp;#8217;s probably one way to annoy the living bejeezus out of people that you&amp;#8217;ve never thought of.&lt;/p&gt;


	&lt;p&gt;To demonstrate, simply visit any Chinese website, such as the &lt;a href=&quot;http://www.bank-of-china.com&quot;&gt;Bank of China&lt;/a&gt; or something else such as &lt;a href=&quot;http://chinaren.com&quot; title=&quot;中国人&quot;&gt;Chinaren&lt;/a&gt;.  Don&amp;#8217;t worry if you can&amp;#8217;t see the characters, they&amp;#8217;re not important for this experiment. (Windows XP users can add them by going to Control Panel /International and installing the Asian Font Pack, while Vista and Mac users will have all these fonts installed already).&lt;/p&gt;


	&lt;p&gt;Once you have one of these pages up in your browser window, click on a link or two.  Click on some more links on those pages.  Try to get back to where you came from.  Within minutes, you&amp;#8217;ll have at least a dozen browser windows littering your desktop, or at best, for those Firefox users with the correct settings, dozens of tabs.&lt;/p&gt;


	&lt;p&gt;You could be forgiven for thinking that this was specific to a few sites with particularly bad design.  And you&amp;#8217;d be totally wrong.  This is completely endemic here in local website design, and is how the locals think that the &amp;#8220;Internets&amp;#8221; should work.  Indeed, there is almost no concept of forward or back button usage any more, and it is not uncommon to see users with well over twenty browser windows littering their desktop at any given time.  While Windows users can at least expect the Task Bar to group similar windows, Mac users just end up using the mouse to move the windows out of the way until needed later, or until they just close the browser application completely.&lt;/p&gt;


	&lt;p&gt;Ultimately, the problem becomes such that, if you want to fix the site design to &lt;em&gt;not&lt;/em&gt; do things this way, you will confuse your user.  When they  click to go to a new page, and they then subsequently finish visiting it, they will close the browser window and proceed to go looking through their other browser windows until they find the one from whence (they hope) they came.&lt;/p&gt;


	&lt;p&gt;The only thing I can say? At least &lt;a href=&quot;http://komoo.com&quot;&gt;blatent ripoffs&lt;/a&gt; of &lt;a href=&quot;http://twitter.com&quot;&gt;other sites&lt;/a&gt; on the internet don&amp;#8217;t seem to have felt compelled to introduce this behaviour into their clones.  For everybody else, it&amp;#8217;s going to take a while to change this design.&lt;/p&gt;</description>
            
            <pubDate>Thu, 07 Jun 2007 19:27:35 -0700</pubDate>
        </item>
            
        <item>
            <title>When MySQL Attacks!!!</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/When+MySQL+Attacks%21%21%21/4hjx</link>
            <description>&lt;h3&gt;The Setup&lt;/h3&gt;


	&lt;p&gt;Imagine, if you will, the following scenario:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;You design a whole new database schema for your cool new scalable web-application. You&amp;#8217;re using MySQL and the InnoDB datbase engine for everything, because your schema is so cool it uses all sorts of foreign keys and transactions and the like.&lt;/li&gt;
		&lt;li&gt;You quickly set up MySQL and get your application going with your new schema on your development staging machine.&lt;/li&gt;
		&lt;li&gt;You get MySQL up and running on your live server, play around with it for a bit to make sure it&amp;#8217;s working, and then set up a &lt;em&gt;my.cnf&lt;/em&gt; file with all sorts of caching and security goodies in it.&lt;/li&gt;
		&lt;li&gt;You do a backup from your dev machine, restore it to the live server, and ta-daa!!! Your web application is up and running on your live server.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;What you might not have noticed, especially if you &amp;#8211; like me &amp;#8211; have a few thousands rows of data, is that MySQL might have screwed you along the way and not really told you all that clearly.&lt;/p&gt;


	&lt;h3&gt;The Problem&lt;/h3&gt;


	&lt;p&gt;After a few days of operation on my live server, I started to notice a few weird things&amp;#8212;foreign keys weren&amp;#8217;t being enforced properly, and there were some values in the database that probably shouldn&amp;#8217;t have been possible.  I furrowed my brows and put it on my list of stuff to investigate.&lt;/p&gt;


	&lt;p&gt;Well, yesterday, I added a new table to the database, and it went something like this:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
mysql&amp;gt; CREATE TABLE Fudgecicles
&amp;gt;(
&amp;gt;  id INTEGER AUTO_INCREMENT PRIMARY KEY,
&amp;gt;  value VARCHAR(255) NOT NULL,
&amp;gt;)
&amp;gt;ENGINE = InnoDB;

Query OK, 0 rows affected, 1 warning (0.10 sec)
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Where did that warning come from?&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
mysql&amp;gt; SHOW WARNINGS;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;It is here that MySQL tells me:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
+---------+------+-----------------------------------------------------+
| Level   | Code | Message                                             |
+---------+------+-----------------------------------------------------+
| Warning | 1266 | Using storage engine MyISAM for table &#039;Fudgecicles&#039; |
+---------+------+-----------------------------------------------------+
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Augh! No! Bad! Bad, MySQL, Bad!  Why on earth would it do that?  I didn&amp;#8217;t misspell InnoDB or even use &amp;#8220;incorrect&amp;#8221; casing in the name.  There&amp;#8217;s nothing wrong with the schema I specified and I&amp;#8217;ve done this hundreds of times before.&lt;/p&gt;


	&lt;p&gt;Well, after some research, I then tried the following:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
mysql&amp;gt; SHOW ENGINES;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;And MySQL helpfully gave me the following:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
+------------+---------+----------------------------------------------------------------+
| Engine     | Support | Comment                                                        |
+------------+---------+----------------------------------------------------------------+
| MyISAM     | DEFAULT | Default engine as of MySQL 3.23 with great performance         |
| MEMORY     | YES     | Hash based, stored in memory, useful for temporary tables      |
| InnoDB     | DISABLED| Supports transactions, row-level locking, and foreign keys     |
| BerkeleyDB | NO      | Supports transactions and page-level locking                   |
| BLACKHOLE  | NO      | /dev/null storage engine (anything you write to it disappears) |
| EXAMPLE    | NO      | Example storage engine                                         |
| ARCHIVE    | YES     | Archive storage engine                                         |
| CSV        | NO      | CSV storage engine                                             |
| ndbcluster | NO      | Clustered, fault-tolerant, memory-based tables                 |
| FEDERATED  | NO      | Federated MySQL storage engine                                 |
| MRG_MYISAM | YES     | Collection of identical MyISAM tables                          |
| ISAM       | NO      | Obsolete storage engine                                        |
+------------+---------+----------------------------------------------------------------+
12 rows in set (0.00 sec)

&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The InnoDB database engine had been disabled somewhere along the way and I hadn&amp;#8217;t even noticed.  It is enabled, by default, on the standard Linux and Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; MySQL binaries that I&amp;#8217;ve been downloading.  So something changed along the way that made this all stop.&lt;/p&gt;


	&lt;p&gt;Far worse, I then began to worry about my existing tables, all of which we supposed to be InnoDB.  Upon executing the following for each of them:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
mysql&amp;gt; SHOW CREATE TABLE Fudgecicles;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;I would see something like:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
| Table       | Create Table
| Fudgecicles | CREATE TABLE `Fudgecicles` (
  `id` int(11) NOT NULL auto_increment,
  `value` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Sure enough, every single one of my tables was MyISAM, and not the InnoDB it was supposed to be.&lt;/p&gt;


	&lt;h3&gt;The Reason&lt;/h3&gt;


	&lt;p&gt;The problem turns out to be that InnoDB is somewhat finicky about &lt;em&gt;my.cnf&lt;/em&gt; settings, and will frequently refuse to operate if settings change in this file in such a way that makes any existing data incompatible with the way it would write new data.&lt;/p&gt;


	&lt;p&gt;In my case, it turns out that changing the settings for the InnoDB binary data and log file sizes were somehow incompatible with the existing binary data and log files (&lt;em&gt;ibdata1&lt;/em&gt; and &lt;em&gt;ib_logfileX&lt;/em&gt;).  Upon starting the server, InnoDB finds this inconsistent state and simply refuses to start up.  This is the first problem.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;The second, and far more serious problem,&lt;/strong&gt; is that MySQL just switches the database persistence engine on you and only provides a little warning.  If you&amp;#8217;re loading in thousands &amp;#8211; if not tens of thousands &amp;#8211; of rows, those warnings are easily lost in the scroll-a-thon that ensues.  This is bad behaviour.  MySQL should simply refuse to create your table if your selected persistence engine is not available.&lt;/p&gt;


	&lt;h3&gt;The Solution&lt;/h3&gt;


	&lt;p&gt;Fixing this problem involved three parts.  The first, and easiest, is to get the InnoDB engine back.  You have two choices:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;You can either revert to the original settings you had for the &lt;em&gt;my.cnf&lt;/em&gt; file to remove the inconsistent state that is freaking out poor ole&amp;#8217; InnoDB.&lt;/li&gt;
		&lt;li&gt;You can delete the &lt;em&gt;idbdata1&lt;/em&gt; and &lt;em&gt;ib_logfileX&lt;/em&gt; files with the inconsistent sizes, thus removing in a different way the same inconsistent state, and allowing InnoDB to startup with your new (and presumably better) configuration values in &lt;em&gt;my.cnf&lt;/em&gt;.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;I chose the second method.&lt;/p&gt;


	&lt;table&gt;
		&lt;tr&gt;
			&lt;td style=&quot;background: #fbb; padding: 0.6em;&quot;&gt; WARNING:  Using this second method can result in data-loss if you&amp;#8217;re not careful.  Some database engines store things in the binary data and log files before writing them to the actual table files, and if they&amp;#8217;re deleted, you might lose those changes.  I only selected this path because all my tables were MyISAM, I had a full backup, and spent a good 10 minutes after deleting the files verifying that all data were correctly restored.&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;




	&lt;p&gt;You then stop and restart the MySQL database engine, and InnoDB will be back. You can verify that all is well in InnoDB land by executing:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
mysql&amp;gt; SHOW InnoDB STATUS;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;And you will receive a gloriously long and detailed set of information on how things are going.&lt;/p&gt;


	&lt;p&gt;Part two of the process involved converting my tables back to InnoDB.&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
mysql&amp;gt;  ALTER TABLE FishSticks ENGINE = InnoDB;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;This proves to be tedious and time consuming, as you cannot simply go from table A to table Z doing the conversion &amp;#8211; because of the foreign keys and references, they have to be done in the right order.  When one of the &lt;code&gt;ALTER TABLE&lt;/code&gt; statements fails, you can find out what happened by re-executing the &lt;code&gt;SHOW InnoDB STATUS&lt;/code&gt; command &amp;#8211; it will tell you why it wouldn&amp;#8217;t convert the table to InnoDB.&lt;/p&gt;


	&lt;p&gt;But, eventually, I got them all done.  It was then that I noticed that none of the foreign keys were set up properly any more.&lt;/p&gt;


	&lt;p&gt;So, the last step of the process is to re-establish the &lt;span class=&quot;caps&quot;&gt;FOREIGN&lt;/span&gt; KEYs.  I did this by, for each foreign key in each table I had, executing the following commands:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
mysql&amp;gt; ALTER TABLE FishSticks DROP KEY [dead foreign key name];
mysql&amp;gt; ALTER TABLE FishSticks ADD FOREIGN KEY (keyname) REFERENCES Table (fieldname);
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The good news is that saving my database and getting back to all sorts of InnoDB goodness only took about an hour in total, for about 30 tables or so.&lt;/p&gt;


	&lt;p&gt;However, if MySQL had simply reported an error a few days earlier instead of blithely just switching tables types behind the scenes, I might have avoided this whole mess in the first place.  Oh well, at least I learned a few neat little commands I can play around with now!  Lesson learned!&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s to hoping that this article helps some other folks solve the same problem a bit quicker!&lt;/p&gt;</description>
            
            <pubDate>Fri, 20 Apr 2007 23:34:13 -0700</pubDate>
        </item>
            
        <item>
            <title>Setting up, Configuring, and Using Kannel to send/receive SMS messages</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Setting+up%2C+Configuring%2C+and+Using+Kannel+to+send%2Freceive+SMS+messages/3e0s</link>
            <description>&lt;p&gt;I recently had the oppportunity (necessity) to set up a web application that interacted with many of the users through &lt;span class=&quot;caps&quot;&gt;SMS&lt;/span&gt; messages in addition to the more traditional &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; interface.  While there are a number of possible software solutions for &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modems on Windows, on Unix-like platforms the most commonly used one is Kannel.  It also has the advantage of being open source and thus very, very free.&lt;/p&gt;


	&lt;p&gt;However, setting, configuring, and using Kannel tends to be a bit tricky.  I&amp;#8217;m writing this article (&lt;em&gt;almost&lt;/em&gt; a &lt;span class=&quot;caps&quot;&gt;HOWTO&lt;/span&gt;) in an attempt to help out anybody who&amp;#8217;s undertaking the process themselves and might be able to get some tips and tricks from this.  I expect this to not be a terribly popular article, but if I ever need to set this stuff up myself in the future, then I&amp;#8217;ll have it written down somewhere at least!&lt;/p&gt;


	&lt;p&gt;Most of the instructions here will work on any Unix platform, such as Linux, FreeBSD, or Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;.  It&amp;#8217;s worth noting that I got nearly everything working with &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;, only to be thwarted at the very end because Mac&amp;#8217;s no longer have serial ports to use &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modems.  You could, however, easily use some of the more advaned &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; based &lt;span class=&quot;caps&quot;&gt;SMS&lt;/span&gt; services on a Mac server of some sort.&lt;/p&gt;


	&lt;h2&gt; The Scenario&lt;/h2&gt;


	&lt;p&gt;The web site written was a discounting service oriented around cell phones.  Users would send the site a message, and then receive a discount at local venues.   They could go to the site on the intarwebs to see their total savings and learn about more venues.&lt;/p&gt;


	&lt;p&gt;The usage pattern was always:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;User sends us a message.&lt;/li&gt;
		&lt;li&gt;We might send them a reply after processing it.&lt;/li&gt;
		&lt;li&gt;We might also periodically need to be able to send the user a message for other purporses, such as party invitations, etc (based on their preferences).&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Downloading and Compiling&lt;/h2&gt;


	&lt;p&gt;Kannel is trivially easy to download and compile.   You visit &lt;a href=&quot;http://kannel.org&quot;&gt;the Kannel.org website&lt;/a&gt; and download the latest and greatest &lt;em&gt;gateway-1.X.Y.tar.gz&lt;/em&gt; file.&lt;/p&gt;


	&lt;p&gt;From there:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
# mkdir src
# cd src
# tar xfz ../downloads/gateway-1.4.1.tar.gz
# cd gateway-1.4.1
# configure --prefix=/usr/local/kannel
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;I chose to install to &lt;code&gt;/usr/local/kannel&lt;/code&gt; just because I&amp;#8217;m that kind of guy who likes to keep everything reasonably separated and organised.  You&amp;#8217;re free to put it anywhere.&lt;/p&gt;


	&lt;p&gt;Compile and install.&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
# make
# sudo make install
password: **************
&lt;/code&gt;
&lt;/pre&gt;

	&lt;h2&gt;Configuration Files&lt;/h2&gt;


	&lt;p&gt;You can be forgiven for thinking Kannel is trivially easy thus far&amp;#8212;it really is that easy to download, compile, and install.  Unfortunately, here is where things get tricky.&lt;/p&gt;


	&lt;p&gt;You now need to set up a configuration file.  This file has a zillion options to support all of the possible and powerful ways in which Kannel can be used.  I will be showing strictly how I set it up for the &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modem we had in the office (It&amp;#8217;s a Siemens &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modem connected to a serial port, and works quite well).&lt;/p&gt;


	&lt;p&gt;The basic smskannel.conf (in the &lt;code&gt;gw/&lt;/code&gt; directory) has much of the information we want, but we&amp;#8217;ll need to add a few things for our &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modems and to interact with our web server correctly.&lt;/p&gt;


	&lt;p&gt;Configuration is divided into a few key groups, each representing the key parts of the kannel system, including the server that handles sending and receving the actual SMSes (bearerbox) and the system that handles the final dispatching to your scripts (smsbox).&lt;/p&gt;


	&lt;h3&gt;The core Group&lt;/h3&gt;


	&lt;p&gt;The first part of the file is the &amp;#8220;core&amp;#8221; group, and the default is pretty close to what we want:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
group = core
admin-port = 13000
smsbox-port = 13001
admin-password = bar
#log-file = &quot;/tmp/kannel.log&quot;
#log-level = 0
box-deny-ip = &quot;*.*.*.*&quot;
box-allow-ip = &quot;127.0.0.1&quot;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;You&amp;#8217;ll want to change the password of course, but everything else is nearly standard.  We are assuming that all communication to the kannel server will come from the same physical computer (127.0.0.1).    You can set a log file if you are going to be running kannel as a service on your server, or you can just redirect stdout to some file.&lt;/p&gt;


	&lt;p&gt;Be aware that kannel has various log levels, ranging from 0, which displays information that is only of interest when you&amp;#8217;re in the development and debugging phases, to 4, which only displays critical errors and problems.  I tend to develop at level 0 and run live servers at level 1.  Disk space is cheap.&lt;/p&gt;


	&lt;h3&gt;The smsc Group&lt;/h3&gt;


	&lt;p&gt;Kannel supports a pretty insane number of ways of sending and receiving SMSes, ranging from &lt;span class=&quot;caps&quot;&gt;SMS&lt;/span&gt; services over &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;, to a fake &lt;span class=&quot;caps&quot;&gt;SMS&lt;/span&gt; centre for testing/development purposes, to &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modems, which is what I have used and is the &lt;em&gt;smsc&lt;/em&gt; module.  These modems use &lt;code&gt;AT&lt;/code&gt;-style modem commands and typically hook up over the serial port.  To get this going, I set up the smsc group in the smskannel.conf file:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
group = smsc
smsc = at
modemtype = auto
device=/dev/ttyS0
my-number = 123123123123
connect-allow-ip = 127.0.0.1
log-level = 0
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The &lt;code&gt;my-number&lt;/code&gt; field contains the number of your &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modem&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;SIM&lt;/span&gt; chip.  Again, I only allow connections from my local server, and the Ubuntu Linux serial port is on &lt;code&gt;/dev/ttyS0&lt;/code&gt;.&lt;/p&gt;


	&lt;h3&gt;The smsbox Group&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;smsbox&lt;/code&gt; group helps configure the part of the system that dispatches SMSes received by the core &lt;span class=&quot;caps&quot;&gt;SMS&lt;/span&gt; or receives SMSes before they&amp;#8217;re sent out.  I honestly don&amp;#8217;t fully understand what this group &lt;em&gt;really&lt;/em&gt; does, but it&amp;#8217;s necessary, and pretty trivial to set up.&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
group = smsbox
bearerbox-host = 127.0.0.1
sendsms-port = 13013
global-sender = 123123123123
log-level = 0
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The &lt;code&gt;global-sender&lt;/code&gt; field is the outgoing-number of your &lt;span class=&quot;caps&quot;&gt;GSM&lt;/span&gt; modem, which for me is the same as the &lt;code&gt;my-number&lt;/code&gt; field above.&lt;/p&gt;


	&lt;h3&gt;The Sendsms Group&lt;/h3&gt;


	&lt;p&gt;This group is what allows your web applications to send &lt;span class=&quot;caps&quot;&gt;SMS&lt;/span&gt; messages using Kannel.  They do this via simple &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; requests, and configuration here basically requires a user name and password:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
group = sendsms-user
username = kanneluser
password = df89asj89I23hvcxSDasdf3298jvkjc839
concatenation= true
max-messages = 10
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Since the password is semi-plain and unprotected here, I tend to use one that is complicated and nearly impossible to remember, but quite different from any other passwords that I actualy use for login accounts and the like.&lt;/p&gt;


	&lt;h3&gt;Getting the Messages to your application&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;sms-service&lt;/code&gt; group configures how Kannel gets messages to your web application.  You are allowed to specify a number of these groups, each of which can &amp;#8220;catch&amp;#8221; incoming messages based on various criteria.  My application had &lt;em&gt;all&lt;/em&gt; messages go to one processing script, so I just set up one group that caught all incoming messages.&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
group = sms-service
keyword =
keyword-regex = .*
catch-all = yes
max-messages = 0
get-url = &quot;http://localhost/sms?phone=%p&amp;#38;text=%a&quot;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;This particular configuration has Kannel set up to use an &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; &lt;code&gt;GET&lt;/code&gt; request to send the message to my application.  The param &lt;code&gt;phone&lt;/code&gt; contains the phone number of the sender and the &lt;code&gt;text&lt;/code&gt; parameter contains their entire message.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;NOTE&lt;/span&gt;:&lt;/strong&gt; The &lt;code&gt;max-messages&lt;/code&gt; value was particularly tricky and critical for me:  When I first set up Kannel and tested sending messages, I would always get back &lt;code&gt;&#039;&amp;lt;Empty reply from service provider&amp;gt;&#039;&lt;/code&gt;.  Setting &lt;code&gt;max-messages&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt; tells Kannel to never send a reply directly from the incoming message (you can, of course, initiate your own response later, of course).&lt;/p&gt;


	&lt;h3&gt;Finally, Setting up the modems&lt;/h3&gt;


	&lt;p&gt;Kannel and &lt;em&gt;smsc&lt;/em&gt; tends to be pretty good at figuring out everything about your modem by yourself, but you can help them out by including &lt;em&gt;modems.conf&lt;/em&gt; in your &lt;em&gt;smskannel.conf&lt;/em&gt; file as I did:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
include = &quot;/usr/local/kannel/modems.conf&quot;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;h2&gt; Running the Server&lt;/h2&gt;


	&lt;p&gt;The hard part is done;  all we have to do now is copy over the config files and start the service up:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;

# cd /usr/local/kannel
# cp ~/src/gateway-1.4.1/smskannel.conf .
# cp ~/src/gateway-1.4.1/gw/modems.conf .
# sbin/bearerbox -v 0 smskannel.conf &amp;#38;
# sbin/smsbox -v 0 smskannel.conf &amp;#38;

&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;I tend to run the last two commands in two separate shell windows when developing/debugging so that I can see the output from the two programs clearly and use the information to help me figure out what&amp;#8217;s going on (level 0 really tells you a lot).&lt;/p&gt;


	&lt;h2&gt;Receiving Messages&lt;/h2&gt;


	&lt;p&gt;Kannel will simply call the &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; you told it to in the &lt;code&gt;sms-service&lt;/code&gt; group and you can process this with whatever &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; server environment you want.  We&amp;#8217;re using &lt;span class=&quot;caps&quot;&gt;LAMP&lt;/span&gt; right now, but, again, any will do.  The incoming phone number and message are in &lt;code&gt;GET&lt;/code&gt; parameters.  You can, if you want, configure the &lt;code&gt;sms-service&lt;/code&gt; to send them as &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; messages as well.&lt;/p&gt;


	&lt;h2&gt;Sending Messages through Kannel&lt;/h2&gt;


	&lt;p&gt;The final part our puzzle is to send outgoing &lt;span class=&quot;caps&quot;&gt;SMS&lt;/span&gt; messages through Kannel, and has only one little twist. It is also done via an &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; interface.  It requires you to be a little careful about the character set you use.  I found I had the most success by using the &lt;span class=&quot;caps&quot;&gt;UCS&lt;/span&gt;-2 character set.   In &lt;span class=&quot;caps&quot;&gt;PHP5&lt;/span&gt;, you can easily use the &lt;code&gt;iconv&lt;/code&gt; function to do this for you.&lt;/p&gt;


	&lt;p&gt;Since I send both English and Chinese messages, my &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; scripts and langugage string files are all &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8.  Here is the code I use to send messages:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;

 function sendSmsMessage($in_phoneNumber, $in_msg)
 {
   $url = &#039;/cgi-bin/sendsms?username=&#039; . CONFIG_KANNEL_USER_NAME
          . &#039;&amp;#38;password=&#039; . CONFIG_KANNEL_PASSWORD
          . &#039;&amp;#38;charset=UCS-2&amp;#38;coding=2&#039;
          . &quot;&amp;#38;to={$in_phoneNumber}&quot;
          . &#039;&amp;#38;text=&#039; . urlencode(iconv(&#039;utf-8&#039;, &#039;ucs-2&#039;, $in_msg));

   $results = file(&#039;http://&#039;
                   . CONFIG_KANNEL_HOST . &#039;:&#039;
                   . CONFIG_KANNEL_PORT . $url);
 }

&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;To make this work, of course, you need to have &lt;code&gt;allow_url_fopen&lt;/code&gt; set to &lt;code&gt;On&lt;/code&gt;.&lt;/p&gt;


	&lt;h2&gt; That&amp;#8217;s It&lt;/h2&gt;


	&lt;p&gt;That&amp;#8217;s pretty much it.  This has been a pretty dry article, but it does contain everything you need to get Kannel up and running and operational.   The manual actually does contain everything you could possibly want to know, so keep digging in there if you&amp;#8217;re stuck.  Finally, there are mailing lists at &lt;a href=&quot;kannel.org&quot;&gt;kannel.org&lt;/a&gt; which tend to be quite helpful as well.&lt;/p&gt;


	&lt;p&gt;Good luck!&lt;/p&gt;</description>
            
            <pubDate>Fri, 13 Apr 2007 22:25:13 -0700</pubDate>
        </item>
            
        <item>
            <title>Why I love computers</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Why+I+love+computers/0m95</link>
            <description>&lt;p&gt;I&amp;#8217;m just beginning a short little contract here in China for a month or so to pay some bills and help a friend out.  Part of doing work in the computer industry in China is that 1000$ &lt;span class=&quot;caps&quot;&gt;USD&lt;/span&gt; for a computer is an outrageous sum of money.  Those of us with Apples are either reckless spendthrifts or simply lucky beyond belief (Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; itself is simply not understood &amp;#8230; is that a program that runs on top of Windows?).  So, this morning, when one of my coworker&amp;#8217;s computer broke, I groaned.  Not only was it likely to be a huge hassle, but the likelihood of having spare parts or another working computer were quite remote.&lt;/p&gt;


	&lt;p&gt;In short, he had no network. The cable lights simply did not come on.  We switched cables.  We unplugged and re-plugged in everything in the office.  We uninstalled and re-installed drivers.  We fiddled and diddled with Windows ad nauseum.  We stole other departments&amp;#8217; switches.  No joy.&lt;/p&gt;


	&lt;p&gt;Finally, in an act of desperation, I opened the computer up, tapped the network port aluminum housing a few times, looked sagely at at the current state of affordable PC hardware (it &lt;em&gt;is&lt;/em&gt; pretty cool looking inside those things), and then tried again &amp;#8230;.   it works fine now.&lt;/p&gt;


	&lt;p&gt;What the&amp;#8212;???&lt;/p&gt;</description>
            
            <pubDate>Mon, 19 Mar 2007 11:51:59 -0700</pubDate>
        </item>
            
        <item>
            <title>Weird Cocoa Errors 101</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Weird+Cocoa+Errors+101/z6dy</link>
            <description>&lt;p&gt;The other day, I was working on JustLooking, changing the appearance and the like of a couple of dialogs.   As I ran the programs and went to show the dialogs (&amp;#8220;panels&amp;#8221; in the local terminology), nothing would show and I&amp;#8217;d get an error in my XCode results window:&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;&quot;Unknown class &#039;CustomCombo&#039; in nib file. using &#039;NSObject&#039; instead.&quot;&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;I spent the next half hour trying to figure out why Interface Builder didn&amp;#8217;t know about this class:  it was there in the class inspector, and the ui widgets were correctly set up to use that new class, and all the hookups in the UI also seemed correct.&lt;/p&gt;


	&lt;p&gt;Well, I finally figured out:  when I first developed the class, I had some errors in it, but wanted to test a few things out in my program elsewhere.  So I had unchecked it in XCode, telling the &lt;span class=&quot;caps&quot;&gt;IDE&lt;/span&gt; not to compile and link it.&lt;/p&gt;


	&lt;p&gt;Thus, when Cocoa tried to load the &lt;span class=&quot;caps&quot;&gt;NIB&lt;/span&gt; file, it couldn&amp;#8217;t find the definition for the class, and just put in NSObject instead.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s to hoping that this blog entry saves somebody that 30 minutes I spent on that one.&lt;/p&gt;</description>
            
            <pubDate>Thu, 08 Mar 2007 20:52:18 -0800</pubDate>
        </item>
            
        <item>
            <title>PHP Tricks and Traps II:  Variable Expansion and Regular Expressions</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/PHP+Tricks+and+Traps+II%3A++Variable+Expansion+and+Regular+Expressions/zghg</link>
            <description>&lt;p&gt;Thanks to Keith from the UK for pointing out something odd in my book that doesn&amp;#8217;t seem to work as it did in earlier versions of &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;:&lt;/p&gt;


	&lt;p&gt;If you have a regular expression (I use the &lt;span class=&quot;caps&quot;&gt;POSIX&lt;/span&gt; ones almost exclusively since they&amp;#8217;re &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8 aware whereas the Perl ones were not when last I inquired), and you want to set a range for the number of matches on a particular expression you can use the syntax:&lt;/p&gt;


&lt;code&gt;
&lt;pre&gt;
$expr = &#039;[a-zA-Z]{5,50}&#039;;        // matches between 5 (incl) and 50 (incl) letters
&lt;/pre&gt;
&lt;/code&gt;

	&lt;p&gt;Now, the problem is:  what if you want to have the number of characters in the range be &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; variables that you can set in a configuration file or some such thing?  Your first attempt, and what I used in my book, might be:&lt;/p&gt;


&lt;code&gt;
&lt;pre&gt;
$expr = &quot;[a-zA-Z]\{$min,$max}&quot;;        // double quotes for var expansion
&lt;/pre&gt;
&lt;/code&gt;

	&lt;p&gt;And you would get a wonderfully annoying error message from the &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; engine:&lt;/p&gt;


&lt;code&gt;
&lt;pre&gt;
Parse error: syntax error, unexpected &#039;,&#039;, expecting &#039;}&#039; in Filename on line 5
&lt;/pre&gt;
&lt;/code&gt;

	&lt;p&gt;No amount of backslashes will fix this problem.  It turns out that the &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; parser consumes &lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; characters when performing complex variable expansion, so &amp;#8230;. all you have to do is add an extra set around each of the variables you wish to expand.  &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; leaves the other two alone:&lt;/p&gt;


&lt;code&gt;
&lt;pre&gt;
$expr = &quot;[a-zA-Z]{{$min},{$max}}&quot;;        // extra { }s are consumed.
&lt;/pre&gt;
&lt;/code&gt;

	&lt;p&gt;And what you are left with is a wonderfully working regular expression.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:48 -0800</pubDate>
        </item>
            
        <item>
            <title>Taking the Fun out of Buying a new Computer</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Taking+the+Fun+out+of+Buying+a+new+Computer/zghf</link>
            <description>&lt;p&gt;In normal times, buying a new computer is a rather fun experience.  In addition to the endorphin rush caused by plonking down a huge wad of cash for such a small &amp;#8211; but often 好看 (that&amp;#8217;s Chinese for good looking) &amp;#8211; piece of hardware, you get to take it home and play with it and discover all the new and fun things that are different about the new toy.  Even if it&amp;#8217;s still running Microsoft Windows, your new vendor has probably come up with some new set of stuff to include with the machine.   Or, far more common with me, my last attempt to finally come up with the &amp;#8220;ultimate organisation of my hard disk&amp;#8482;&amp;#8221; was a miserable failure, and I&amp;#8217;m excited about trying out something new.&lt;/p&gt;


	&lt;p&gt;So, imagine my disappointment when I recently upgraded my 15&amp;#8221; Powerbook G4 to a shiny new 15&amp;#8221; Macbook Pro.&lt;/p&gt;

In short, my upgrade experience was:

	&lt;ul&gt;
	&lt;li&gt;Plug in new computer, run through annoying Apple registration sequence (Tip:  If you indicate in one of the first steps that the computer will not be connected to the Internet, you can make it so that the registration will not be sent).&lt;/li&gt;
		&lt;li&gt;Run migration wizard from the old Powerbook to the new Macbook Pro (this involves clicking a few buttons and connecting the two machines by FireWire).&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Yes, about an hour later (35GB of  iTunes and image data takes a while to transfer from one 5400RPM laptop drive to another), my new machine, appeared &lt;i&gt;exactly&lt;/i&gt; the same as the old one.  My desktop, my language settings, all my files, &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; keys, &lt;i&gt;svn&lt;/i&gt; and source enlistments, and more.&lt;/p&gt;


	&lt;p&gt;What&amp;#8217;s worse, all of the software on the old machine was Universal Binaries, so I didn&amp;#8217;t even need to install any new software.  It if weren&amp;#8217;t for the fact that &lt;a href=&quot;http://chipmunkninja.com/justlooking11&quot;&gt;JustLooking&lt;/a&gt; compiled in less than 30 seconds instead of well over 2 minutes, I might not have even noticed right away.&lt;/p&gt;


	&lt;p&gt;I did also notice after a bit of experimenting that I can finally watch &lt;span class=&quot;caps&quot;&gt;HDTV&lt;/span&gt; movies (720p and 1080i) at more than 2 frames a second, and that instead of being completley unable to play Civ IV, I can now play it at 1900&amp;#215;1200 with &lt;i&gt;all&lt;/i&gt; features and whizzy 3D goodies turned on.  I&amp;#8217;ve also noticed that the fabled heat problems of the &lt;span class=&quot;caps&quot;&gt;MBP&lt;/span&gt; have not materialised on my machine.  After a copule of hours of gaming, the machine is no warmer than the G4.&lt;/p&gt;


	&lt;p&gt;However, the upgrade itself was a complete  and utter disappointment.  No temporary disruption in productivity, nor any hours spent trying to figure out how to migrate all of my data over.  In short, no excuse to do anything other than just go back to work.&lt;/p&gt;


	&lt;p&gt;Thanks Apple.  Jerks.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:48 -0800</pubDate>
        </item>
            
        <item>
            <title>Rotating an NSImage object in Cocoa</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Rotating+an+NSImage+object+in+Cocoa/zgha</link>
            <description>&lt;p&gt;I recently started working on an image viewing program for Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; using Cocoa, and one of the features I decided to add was the ability to rotate images in 90° increments.   I did some searching on the internet, and found a few things:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Some other people who were struggling with the same thing and posted some code snippets.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://lists.apple.com/archives/cocoa-dev/2004/Jul/msg00380.html&quot;&gt;Code for a rotation function&lt;/a&gt; that supports arbitrary rotation and scaling.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/index.html&quot;&gt;Apple Documentation on Drawing&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Neither of the first two was exactly what I wanted&amp;#8212;the first didn&amp;#8217;t quite work, while the second was too complicated and, in order to support arbitrary rotation, created an NSImage object that was way too large.&lt;/p&gt;


	&lt;p&gt;So, after reading the Apple Cocoa Drawing Guide on Using Transforms, I came up with the following code to rotate an NSImage object 90°.  Please note that this function &lt;span class=&quot;caps&quot;&gt;ONLY&lt;/span&gt; supports a clockwise or counterclockwise 90° rotation.  It also returns an object that must be released by the callER.  I&amp;#8217;m not 100% sure if this is standard Objective-C/Cocoa methodology, as I&amp;#8217;m still a bit new to all this stuff.&lt;/p&gt;


	&lt;p&gt;But, without any further ado, here is the rotation function:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
- (NSImage *)rotateIndividualImage: (NSImage *)image clockwise: (BOOL)clockwise
{
    NSImage *existingImage = image;
    NSSize existingSize;

    /**
     * Get the size of the original image in its raw bitmap format.
     * The bestRepresentationForDevice: nil tells the NSImage to just
     * give us the raw image instead of it&#039;s wacky DPI-translated version.
     */
    existingSize.width = [[existingImage bestRepresentationForDevice: nil] pixelsWide];
    existingSize.height = [[existingImage bestRepresentationForDevice: nil] pixelsHigh];

    NSSize newSize = NSMakeSize(existingSize.height, existingSize.width);
    NSImage *rotatedImage = [[NSImage alloc] initWithSize:newSize];

    [rotatedImage lockFocus];

    /**
     * Apply the following transformations:
     *
     * - bring the rotation point to the centre of the image instead of
     *   the default lower, left corner (0,0).
     * - rotate it by 90 degrees, either clock or counter clockwise.
     * - re-translate the rotated image back down to the lower left corner
     *   so that it appears in the right place.
     */
    NSAffineTransform *rotateTF = [NSAffineTransform transform];
    NSPoint centerPoint = NSMakePoint(newSize.width / 2, newSize.height / 2);

    [rotateTF translateXBy: centerPoint.x yBy: centerPoint.y];
    [rotateTF rotateByDegrees: (clockwise) ? - 90 : 90];
    [rotateTF translateXBy: -centerPoint.y yBy: -centerPoint.x];
    [rotateTF concat];

    /**
     * We have to get the image representation to do its drawing directly,
     * because otherwise the stupid NSImage DPI thingie bites us in the butt
     * again.
     */
    NSRect r1 = NSMakeRect(0, 0, newSize.height, newSize.width);
    [[existingImage bestRepresentationForDevice: nil] drawInRect: r1];

    [rotatedImage unlockFocus];

    return rotatedImage;
}
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The function works great and correctly rotates the incoming NSImage 90 degrees.  However, People working with JPEGs should probably not save these data to disk in place of existing images, as the function works on the decompressed bits and resaving them can lose more image data.  To truly solve this problem, you should use a &amp;#8220;Lossless &lt;span class=&quot;caps&quot;&gt;JPEG&lt;/span&gt; Image Rotation&amp;#8221; algorithm.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:46 -0800</pubDate>
        </item>
            
        <item>
            <title>Announcing Payjacks, an Object-Oriented PHP/Ajax Web Application Framework</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Announcing+Payjacks%2C+an+Object-Oriented+PHP%2FAjax+Web+Application+Framework/zgg7</link>
            <description>&lt;p&gt;I am happy to announce the immediate availability of Payjacks, currently at version 0.2.0.  Payjacks is a &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;/Ajax web application framework I&amp;#8217;ve written using the object-oriented features in &lt;span class=&quot;caps&quot;&gt;PHP5&lt;/span&gt;+.&lt;/p&gt;


	&lt;p&gt;Payjacks can be downloaded here:&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://chipmunkninja.com/download/payjacks-0.2.0.tar.gz&quot;&gt;http://chipmunkninja.com/download/payjacks-0.2.0.tar.gz&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;What is Payjacks?&lt;/h3&gt;


	&lt;p&gt;Payjacks is an object oriented &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;-Ajax web application framework I&amp;#8217;ve
written to help write robust and organised web applications.  It was
designed to require a minimal amount of effort to get your own web
application up and running, while helping with such tasks as accessing
a (MySQL, currently) database or providing a framework for sending
asynchronous Ajax requests back to the server.&lt;/p&gt;


	&lt;p&gt;Payjacks uses many of the new object-oriented features in &lt;span class=&quot;caps&quot;&gt;PHP 5&lt;/span&gt; to do
its work, and handles most of the details required to run a robust
web application.&lt;/p&gt;

Some of the main features are:

	&lt;ul&gt;
	&lt;li&gt;Fully object-oriented.&lt;/li&gt;
		&lt;li&gt;Support for various types of Asynchronous Ajax requests, including
  submitting forms asynchronous or simply sending your own data strings
  asynchronously&lt;/li&gt;
		&lt;li&gt;Robust error handling and exception handling, allowing for customisable
  error pages and otherwise helping you help your users when things go
  wrong.&lt;/li&gt;
		&lt;li&gt;Support for &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; processing.  Thus, instead of having URLs such as
  &lt;em&gt;http://mysite.blabhalblahblah.com/SomePageName.php?showarticle=getname&lt;/em&gt;
  you can have your site do things like:
  &lt;em&gt;http://mysite.blhablahblah.com/showarticle/name&lt;/em&gt;.  This helps make your application easier to use for power users and helps with search engine indexing.&lt;/li&gt;
		&lt;li&gt;The ability to create simple pages if you just want to test things out
  and don&amp;#8217;t want the hassle of setting up a web application.&lt;/li&gt;
		&lt;li&gt;A full set of samples to show you how to set things up.&lt;/li&gt;
		&lt;li&gt;The framework has been designed from day one with web application
  security in mind.&lt;/li&gt;
		&lt;li&gt;Full support for &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8 and localisable web sites.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;When should I use Payjacks?&lt;/h3&gt;


	&lt;p&gt;I use Payjacks for almost all of my &amp;#8220;web page writing&amp;#8221; these days.  You
can use the SimplePage class to just throw out a single &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;/HTML page,
or you can use the WebApplication class and template off one of the samples
to create more robust web applications.&lt;/p&gt;


	&lt;p&gt;Since Payjacks takes care of so many of the details that many web
application authors simply neglect (error handling, &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; processing,
security details), using it gives you nearly everything you want except for
the actual &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; of your pages.&lt;/p&gt;


	&lt;p&gt;If you want to use asynchronous Ajax requests, Payjacks helps to make this
very easy too.&lt;/p&gt;


	&lt;h3&gt;What does Payjacks &lt;em&gt;not&lt;/em&gt; do?&lt;/h3&gt;


	&lt;p&gt;Payjacks does not help with generation of well-styled &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; or page content.  It merely gives you the framework in which to place your content.
There is nothing preventing you from designing and developing perfectly
secure and robust yet hideously ugly web applications using Payjacks.  It
is for this reason that graphic designers earn their paycheques.  Even
my blog site, &lt;a href=&quot;http://chipmunkninja.com&quot;&gt;http://chipmunkninja.com&lt;/a&gt; is very rudimentary and clearly
shows the limits of my design skills.&lt;/p&gt;


	&lt;h3&gt;Payjacks Requirements&lt;/h3&gt;


	&lt;p&gt;In order to run Payjacks, you need:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;PHP 5&lt;/span&gt;.0 or later.  I&amp;#8217;ve tested on 5.0.[45] and 5.1.4.  &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; needs to have
  mbstring and mbregex built-in for any sites not using strict Latin1
  pages.&lt;/li&gt;
		&lt;li&gt;A web server.  If you want this web server to support the web application
  system that Payjacks is built around, it must have some sort of &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;
  re-writing capability.

	&lt;p&gt;On Apache, this is mod_rewrite, and can easily be compiled into your
Apache build.  I have tested and run this on Apache 1.3.xx and 2.0.yy.&lt;/p&gt;


	&lt;p&gt;For &lt;span class=&quot;caps&quot;&gt;IIS&lt;/span&gt;, there are a number of mod_rewrite clones, ranging from very
free and open source to very expensive and not open source.&lt;/p&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;More&lt;/h3&gt;


	&lt;p&gt;Payjacks is currently version 0.2.0 and should be considered development quality only right now.  I plan on making some minor changes to function signatures in the next few versions (mostly to get rid of some parameters that I &lt;em&gt;thought&lt;/em&gt; I would need for localisation, but have since realised were the wrong way to go about the problem).&lt;/p&gt;


	&lt;p&gt;If you have any bugs, comments, or questions, please do not hesitate to contact me at marcwan&amp;#64;chipmunkninja&amp;#46;com.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:46 -0800</pubDate>
        </item>
            
        <item>
            <title>When Apples go Bad</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/When+Apples+go+Bad/zgg6</link>
            <description>&lt;p&gt;Last night, after a nice weekend of varying activities (yoga, studying, yoga, sleeping), the plan was to lie in bed and read some &lt;a href=&quot;http://developer.apple.com&quot;&gt;Apple Developer Connection&lt;/a&gt; documentation for a while and generally learn more about some stuff I&amp;#8217;ve been working on lately.&lt;/p&gt;


	&lt;p&gt;So, it was with some dismay that I sat down with Samantha&amp;#8217;s PowerBook G4, clicked on Safari and got &amp;#8230; nothing.  The icon bounced twice and then stopped.  System logs showed nothing, and the application appeared to be all fine in its folder in /Applications.&lt;/p&gt;


	&lt;p&gt;Uuuuuh. Now what?  Oh yes, the System Console, in /Application/Utilities.  It gave me the following &lt;strong&gt;very&lt;/strong&gt; helpful message:&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;2006-08-20 22:32:29.825 Safari[249] Unable to load nib file: MainMenu, exiting&lt;/code&gt;&lt;/p&gt;

For those not familiar with Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; (or NeXTStep) development, &lt;acronym title=&quot;Next Interface Builder&quot;&gt;NIB&lt;/acronym&gt; files are files that contain the structure and connections used by the various user Interface elements used by &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; Cocoa applications.  These are usually only modified by the Interface Builder application used to develop applications.

	&lt;p&gt;So what was wrong with mine?  Some searching around the Intarwebs suggested that it might be a permissions thing.  So I fired up the Disk Utility and that said that a bunch of permissions were all wrong (how did &lt;strong&gt;that&lt;/strong&gt; happen?) and fixed them.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://chipmunkninja.com/images/diskutil2.png&quot; title=&quot;It really works...&quot; alt=&quot;It really works...&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;Still no dice with Safari.   There was another button on the Disk Utility to &amp;#8220;Verify Disk&amp;#8221;.  That did not go well.  Lots of red text and scary messages, and finally &amp;#8220;exiting&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;So, in the end, I had to actually boot the PowerBook into single user mode (when the machine is booting up, hold down &lt;span class=&quot;caps&quot;&gt;CMD&lt;/span&gt;/Apple + S), and run&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;/sbin/fsck -fy&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;to get everything working again.  It took running this program twice to get everything fixed, and even then, one of the sub-nib files in the MainMenu.nib/ directory for Safari.app was still corrupted, and had to be copied from somewhere else.  Luckily, we&amp;#8217;ve got another PowerBook G4 here in Beijing, or I would have had to harrass somebody overseas for the file.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://chipmunkninja.com/images/diskutil1.png&quot; alt=&quot;&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;None of this is particularly new, shocking, or difficult to figure out, especially for those who have run various flavours of Unix for some time.  I&amp;#8217;ve just grown so used to my PowerBook being extremely reliable (in three years of owning a Dell Laptop running XP, I never once had half the average uptime I get on my PowerBoook) that it&amp;#8217;s so shocking when there is a problem, I&amp;#8217;m taken off guard.&lt;/p&gt;


	&lt;p&gt;There is an interesting point to be made here though, and that is that there no way Samantha would have been able to figure out and do this by herself.  She still would have had to go to an Apple Geek Lab (or whatever they&amp;#8217;re called) &amp;#8211; of which there are none here in Beijing &amp;#8211; and get somebody to look at it for her, or beg a friend (who might not have known what s/he was doing and suggested &amp;#8220;wiping and reinstalling everything&amp;#8221;).  As nice as it can be to use, personal computing software still has a long way to go.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:45 -0800</pubDate>
        </item>
            
        <item>
            <title>Program Execution in PHP: exec, system, passthru, and shell_exec, oh my!</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Program+Execution+in+PHP%3A+exec%2C+system%2C+passthru%2C+and+shell_exec%2C+oh+my%21/zgg5</link>
            <description>&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; is a sufficiently rich programming environment that it is not common that I truly need to execute external programs on the server on which it executes.  However, every once in a while, this situation &lt;em&gt;does&lt;/em&gt; come along, and for these, it is important to understand the options that &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; provides, what their differences are, and their relative strengths and weaknesses.&lt;/p&gt;


	&lt;p&gt;There are four primary choices for executing external programs in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;The &lt;code&gt;system&lt;/code&gt; function.&lt;/li&gt;
		&lt;li&gt;The &lt;code&gt;exec&lt;/code&gt; function.&lt;/li&gt;
		&lt;li&gt;The &lt;code&gt;shell_exec&lt;/code&gt; function or its syntactic analogue, the &lt;em&gt;backtick operator&lt;/em&gt;, ( ` ).&lt;/li&gt;
		&lt;li&gt;the &lt;code&gt;passthru&lt;/code&gt; function.&lt;/li&gt;
	&lt;/ul&gt;

There is, in fact, a fourth option in &lt;span class=&quot;caps&quot;&gt;PHP 5&lt;/span&gt;, using a new set of functions all prefixed with &lt;code&gt;proc_&lt;/code&gt;, such as &lt;code&gt;proc_open&lt;/code&gt; and &lt;code&gt;proc_close&lt;/code&gt;, but these are quite advanced, and beyond the scope of this article.

	&lt;p&gt;We will first discuss the usage of these three functions in their most basic forms.&lt;/p&gt;


	&lt;h3&gt;The system() Function&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;system&lt;/code&gt; function in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; takes a string argument with the command to execute as well as any arguments you wish passed to that command.  This function executes the specified command, and dumps any resulting text to the output stream (either the &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; output in a web server situation, or the console if you are running &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; as a command line tool).  The return of this function is the &lt;em&gt;last line&lt;/em&gt; of output from the program, if it emits text output.&lt;/p&gt;


	&lt;p&gt;For example:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
// Windows Users replace &quot;ls ...&quot; with &quot;dir ...&quot;
$lastLine = system(&#039;ls /Users/marcwan&#039;);
echo &quot;&amp;lt;br/&amp;gt;LastLine: $lastLine&amp;lt;br/&amp;gt;\\n&quot;;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The output of this command on my system is:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
Desktop Documents Download Library Movies Music Pictures
  Public Sites bin blah.php books make1.png make1.tiff media src
  yici1.png yici1.tiff
LastLine: yici1.tiff
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The return value of the function will be &lt;code&gt;FALSE&lt;/code&gt; if the function completely fails to execute.&lt;/p&gt;


	&lt;p&gt;In addition to the return value of the &lt;code&gt;system&lt;/code&gt; function, however, there is also the question of the &lt;em&gt;return status&lt;/em&gt; of the program being executed (just as functions in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; all have return values (&lt;code&gt;NULL&lt;/code&gt; if you don&amp;#8217;t explicitly choose one), all commands executed in most operating systems also have return values, typically a 32bit integer value).   For those programs you are executing whose return status you wish to know, you can pass a second argument to the &lt;code&gt;system&lt;/code&gt; function, which tells &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; where to put this value.&lt;/p&gt;


	&lt;p&gt;For example:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
// define this variable here so that it can actually be used in the system fn
$returnValue = -1;
system(&#039;ls /Users/marcwan&#039;, $returnValue);
echo &quot;Return Value: $returnValue&amp;lt;br/&amp;gt;\\n&quot;;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The output of this program will be:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
Desktop Documents Download Library Movies Music Pictures
  Public Sites bin blah.php books make1.png make1.tiff media src
  yici1.png yici1.tiff
Return Value: 0
&lt;/pre&gt;
&lt;/code&gt;

	&lt;p&gt;For most modern operating systems, a return value of &lt;code&gt;0&lt;/code&gt; is considered a success, and other values indicate failure.  Some programs will have a range of values to indicate the exact way in which they failed while others will just return &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;-1&lt;/code&gt; to indicate that they were unsuccessful.&lt;/p&gt;


	&lt;h3&gt;The exec() Function&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;system&lt;/code&gt; function is quite useful and powerful, but one of the biggest problems with it is that all resulting text from the program goes directly to the output stream.  There will be situations where you might like to format the resulting text and display it in some different way, or not display it at all.&lt;/p&gt;


	&lt;p&gt;For this, the &lt;code&gt;exec&lt;/code&gt; function in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; is perfectly adapted.  Instead of automatically dumping all text generated by the program being executed to the output stream, it gives you the opportunity to put this text in an array returned in the second parameter to the function:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
// you define this variable here so that it exists for the call to exec
$output = null;

// Windows users: &#039;dir c:\\&#039; or something similar
exec(&#039;ls /Users/marcwan&#039;, $output);
echo &quot;&amp;lt;pre&amp;gt;&quot; . var_export($output, TRUE) . &quot;&amp;lt;/pre&amp;gt;\\n&quot;;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Once again, on my machine, the following output is printed:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
array (
  0 =&amp;gt; &#039;Desktop&#039;,
  1 =&amp;gt; &#039;Documents&#039;,
  2 =&amp;gt; &#039;Download&#039;,
  3 =&amp;gt; &#039;Library&#039;,
  4 =&amp;gt; &#039;Movies&#039;,
  5 =&amp;gt; &#039;Music&#039;,
  6 =&amp;gt; &#039;Pictures&#039;,
  7 =&amp;gt; &#039;Public&#039;,
  8 =&amp;gt; &#039;Sites&#039;,
  9 =&amp;gt; &#039;bin&#039;,
  10 =&amp;gt; &#039;blah.php&#039;,
  11 =&amp;gt; &#039;books&#039;,
  12 =&amp;gt; &#039;make1.png&#039;,
  13 =&amp;gt; &#039;make1.tiff&#039;,
  14 =&amp;gt; &#039;media&#039;,
  15 =&amp;gt; &#039;src&#039;,
  16 =&amp;gt; &#039;yici1.png&#039;,
  17 =&amp;gt; &#039;yici1.tiff&#039;,
)
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Of course, instead of just directly emitting this output, we could instead choose to process it and only emit those files with a &lt;em&gt;&amp;#8217;.png&amp;#8217;&lt;/em&gt; extension, for example:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
foreach ($output as $fileName)
{
  if (strtolower(substr($fileName, -4)) == &#039;.png&#039;)
    echo &quot;&amp;lt;br/&amp;gt;$fileName\\n&quot;;
}
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;And once again, you can get the return code from the &lt;code&gt;exec&lt;/code&gt; function as follows:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
$output = null;
$returnValue = -1;
exec(&#039;ls /Users/marcwan&#039;, $output, $returnValue);
echo &quot;Return Value: $returnValue&amp;lt;br/&amp;gt;\\n&quot;;
echo &quot;&amp;lt;pre&amp;gt;&quot; . var_export($output, TRUE) . &quot;&amp;lt;/pre&amp;gt;\\n&quot;;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;h3&gt;The shell_exec() Function&lt;/h3&gt;


	&lt;p&gt;Most of the programs we have been executing thus far have been, more or less, real programs&lt;sup&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.  However, the environment in which Windows and Unix users operate is actually much richer than this.   Windows users have the option of using the Windows Command Prompt program, &lt;code&gt;cmd.exe&lt;/code&gt; (See Figure 1).  This program is known as a &lt;em&gt;command shell&lt;/em&gt;.&lt;/p&gt;


&lt;img src=&quot;http://chipmunkninja.com/images/cmd.exe.png&quot; title=&quot;The Windows cmd.exe Command Shell&quot; alt=&quot;The Windows cmd.exe Command Shell&quot;/&gt;
	&lt;p style=&quot;text-align:center;&quot;&gt;&lt;strong&gt;Figure 1&amp;#8212;&lt;/strong&gt; The Windows Command Prompt&lt;/p&gt;


	&lt;p&gt;Similarly, Unix (and Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;) users can run a command shell such as &lt;code&gt;sh&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt;, or &lt;code&gt;csh&lt;/code&gt; (see Figure 2).  These are typically quite advanced interactive systems that allow elabourate scripts such as &lt;code&gt;for x in *.png; do echo $x; done&lt;/code&gt; to be executed.&lt;/p&gt;


&lt;img src=&quot;http://chipmunkninja.com/images/Terminal.app.jpg&quot; title=&quot;Apple OS X&#039;s command shell&quot; alt=&quot;Apple OS X&#039;s command shell&quot;/&gt;
	&lt;p style=&quot;text-align:center;&quot;&gt;&lt;strong&gt;Figure 2&amp;#8212;&lt;/strong&gt; bash on Mac &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;&lt;/p&gt;


	&lt;p&gt;On both Windows and Unix, the commands for the various command shells can be put into files and executed by these programs.  On Windows, convention has it that these script file have the extension &lt;em&gt;.cmd&lt;/em&gt; while on Unix it is not uncommon to see &lt;em&gt;.sh&lt;/em&gt;.&lt;/p&gt;


	&lt;p&gt;For those sitautions where we want to run these shell scripts from within &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;, we can use the &lt;code&gt;shell_exec&lt;/code&gt; function, as follows:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;

// lists all .bat files anywhere in the system
$output = shell_exec(&#039;FOR /R C:\\ IN (*.bat) DO echo %x&#039;);   // Windows

// lists all .png files in /Users/marcan only
$output = shell_exec(&#039;for x in /Users/marcwan/*.png; do echo $x; done&#039;); // Unix

echo &quot;&amp;lt;pre&amp;gt;&quot; . var_export($output, TRUE) . &quot;&amp;lt;/pre&amp;gt;\\n&quot;;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;On my system this produces:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
&#039;/Users/marcwan/make1.png
/Users/marcwan/yici1.png
&#039;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; also has a syntactic operator called the backtick operator which does the exact same thing as the &lt;code&gt;shell_exec&lt;/code&gt; function.  Instead of calling the &lt;code&gt;shell_exec&lt;/code&gt; function, you simply wrap the command in the backtick character, &lt;code&gt;`&lt;/code&gt;, which is very different from the single quote character &lt;code&gt;&#039;&lt;/code&gt;.&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;

// lists all .bat files anywhere in the system
$output = `FOR /R C:\\ IN (*.bat) DO echo %x`; // Windows

// lists all .png files in /Users/marcan only
$output = `for x in /Users/marcwan/*.png; do echo $x; done`; // Unix

echo &quot;&amp;lt;pre&amp;gt;&quot; . var_export($output, TRUE) . &quot;&amp;lt;/pre&amp;gt;\\n&quot;;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;It is worth noting that I avoid this operator at all times as it is not easy to spot in code, and I like potential security trouble spots to be as visible as humanly possible.&lt;/p&gt;


	&lt;h3&gt;The passthru() Function&lt;/h3&gt;


	&lt;p&gt;One fascinating function that &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; provides similar to those we have seen so far is the &lt;code&gt;passthru&lt;/code&gt; function.  This function, like the others, executes the program you tell it to.  However, it then proceeds to immediately send the raw output from this program to the output stream with which &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; is currently working (i.e. either &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; in a web server scenario, or the shell in a command line version of &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;).&lt;/p&gt;


	&lt;p&gt;When would this be useful?  When you are working with image files and want to execute a program to show or otherwise manipulate these files.  A most simple example would be as follows:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
/**
 * Windows:
 */
header(&#039;Content-Type: image/bmp&#039;);
passthru(&#039;type c:\\Windows\\zapotec.bmp&#039;);

/**
 * Unix
 */
header(&#039;Content-Type: image/jpg&#039;);
passthru(&#039;cat /Users/marcwan/yici1.png&#039;);
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The result will be an image in your browser.  This is extremely powerful if you want to use some programs to resize or otherwise manipulate image files and then just dump the output to the client.   There are a number of interesting utilities that come with various &lt;span class=&quot;caps&quot;&gt;JPEG&lt;/span&gt; source code distributions that do exactly this and are powerful tools.&lt;/p&gt;


	&lt;h3&gt;Are We Done Yet?&lt;/h3&gt;


	&lt;p&gt;Armed with this basic knowledge, we have a one major thing left to deal with before we go off into the real world and begin using these functions: Security.&lt;/p&gt;


	&lt;table&gt;
		&lt;tr&gt;
			&lt;td style=&quot;background:#c5ffc2;&quot;&gt;Allowing users to specify any portion of the string you pass to the &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;system&lt;/code&gt;, &lt;code&gt;shell_exec&lt;/code&gt;, or &lt;code&gt;passthru&lt;/code&gt; functions is a &lt;strong&gt;huge&lt;/strong&gt; security risk, and you need to plan carefully in advance before allowing any of this.&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;




	&lt;p&gt;For example, the following code is simply a recipe for disaster:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
$output = shell_exec(&#039;cat /webserver/info/user_files/&#039; . $_POST[&#039;user_info_file&#039;]);
echo $output
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;If a malicious user were to set the value of the &lt;code&gt;user_info_file&lt;/code&gt; post variable to &lt;code&gt;bob; cat /etc/passwd&lt;/code&gt;.  The output of both files would now be dumped, which is definitely not in your best interests.&lt;/p&gt;


	&lt;p&gt;There are two key ways which we will get around this:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;We will design our web applications carefully for security.  If we can design the web application in such a way that only we choose the file names and programs that execution functions work with, we have much less to worry about in terms of security.  We can also do our best to isolate any files that we work with and try to limit damage whenever something unexpected occurs.&lt;/li&gt;
		&lt;li&gt;For those cases where we decide that user input is absolutely unavoidable, we will filter the user input extremely heavily and make sure it is as safe as possible before passing it to any of these functions.  I always do the following:
	&lt;ul&gt;
	&lt;li&gt;Absolutely forbid the use of any slash characters, whether it be forward ( / ) or backward ( \ ). I also forbid any user strings from beginning with &lt;code&gt;X:&lt;/code&gt;, where X could be a valid drive letter on the system (Windows only, of course).&lt;/li&gt;
		&lt;li&gt;Use the &lt;code&gt;escapeshellarg&lt;/code&gt; function to further make the parameters safer.  I.e. &lt;code&gt;$output = shell_exec(&quot;cat /web/users/info/&quot; . escapeshellarg($processedUserInfoFile));&lt;/code&gt;&lt;/li&gt;
	&lt;/ol&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;A way in which we are helped by the operating system is that most web servers operate as a user with restricted permission, and thus can only do things that user is permitted to do.&lt;/p&gt;


	&lt;p&gt;One last security note we should mention here is that if your &lt;em&gt;php.ini&lt;/em&gt; file has &lt;code&gt;safe_mode&lt;/code&gt; set to &lt;code&gt;On&lt;/code&gt;, then the &lt;code&gt;shell_exec&lt;/code&gt; function and analagous backtick operator is not available.&lt;/p&gt;


	&lt;h3&gt;Conclusion&lt;/h3&gt;


	&lt;p&gt;We have covered a lot of ground in this article, but we should now have a solid understanding of the various execution functions available to us in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;, as well as how they differ.  While we should be extremely concerned about the security of running programs external to our web server, we can do so in a reasonably safe and controlled manner, which can only be a good thing for our web applications and their customers.&lt;/p&gt;


	&lt;p&gt;&amp;#8212;&lt;/p&gt;


	&lt;p style=&quot;font-size: 8pt;&quot; id=&quot;fn1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; It is worth noting that &lt;code&gt;dir&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt;, and many other commands on Windows are &lt;em&gt;not&lt;/em&gt; programs, but actualy commands built into the &lt;code&gt;cmd.exe&lt;/code&gt; program.  Fortunately the system execution functions are smart enough to know to execute &lt;code&gt;cmd.exe&lt;/code&gt; for you if you ask to execute one of them.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:45 -0800</pubDate>
        </item>
            
        <item>
            <title>StripTags 1.0 Released</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/StripTags+1.0+Released/zgg4</link>
            <description>&lt;p&gt;&lt;a href=&quot;http://chipmunkninja.com/download/striptags-1.0.0.tar.gz&quot;&gt;Download version 1.0 of StripTags for &lt;span class=&quot;caps&quot;&gt;PHP5&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;After some further development over the last couple of weeks, I have released version 1.0 of the StripTags class for &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;This class is designed to replace the &lt;a href=&quot;http://php.net/manual/en/function.strip-tags.php&quot;&gt;strip_tags&lt;/a&gt; function in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;, which does not work particuarly well.  It serves to help website authors avoid cross-site-scripting (XSS) attacks in user-created content, for sites such as blogs or forums where users can enter entries, articles, or comments.&lt;/p&gt;

You can read more about the class and &lt;span class=&quot;caps&quot;&gt;XSS&lt;/span&gt; in general in the following article:

	&lt;p&gt;&lt;a href=&quot;http://chipmunkninja.com/article/striptags&quot;&gt;Helping Prevent &lt;span class=&quot;caps&quot;&gt;XSS&lt;/span&gt; Attacks in &lt;span class=&quot;caps&quot;&gt;PHP5&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;The big new feature change in this version of the class is the ability to find &lt;span class=&quot;caps&quot;&gt;XSS&lt;/span&gt; attacks injected via unicode-enrypted attributes, such as:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
&amp;lt;IMG SRC=&amp;amp;#106;&amp;amp;#97;&amp;amp;#118;&amp;amp;#97;&amp;amp;#115;&amp;amp;#99;&amp;amp;#114;&amp;amp;#105;&amp;amp;#112;&amp;amp;#116;
      &amp;amp;#58;&amp;amp;#97;&amp;amp;#108;&amp;amp;#101;&amp;amp;#114;&amp;amp;#116;&amp;amp;#40;&amp;amp;#39;&amp;amp;#88;&amp;amp;#83;&amp;amp;#83;&amp;amp;#39;&amp;amp;#41;&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;We now successfully find these and neutralise them by inserting extra junk in the attribute string so that they are not processed by client browsers.&lt;/p&gt;


	&lt;p&gt;Please note that this class is not a 100% complete solution to &lt;span class=&quot;caps&quot;&gt;XSS&lt;/span&gt;.  We do not handle all of the ways that &lt;span class=&quot;caps&quot;&gt;XSS&lt;/span&gt; can be achieved through &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; and other forms of style (and thus always recommend that you not permit users to enter &lt;span class=&quot;caps&quot;&gt;STYLE&lt;/span&gt; elements or &amp;#8220;style&amp;#8221; attributes on other elements).  Solving this problem requires significant amount of work and effort, and I believe that if you want to give users that degree of input control, you should have them use a Wiki-language engine such as Textile.&lt;/p&gt;


	&lt;p&gt;The &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;INSTALL&lt;/span&gt; documents have full information on how to use the class as well as what it does and does not do.&lt;/p&gt;


	&lt;p&gt;As always, please feel free to email me with any questions, comments, or bug reports.  I&amp;#8217;ll fix the latter as quickly as I can.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://chipmunkninja.com/download/striptags-1.0.0.tar.gz&quot;&gt;Download version 1.0 of StripTags for &lt;span class=&quot;caps&quot;&gt;PHP5&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:44 -0800</pubDate>
        </item>
            
        <item>
            <title>Google Blocked in China</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Google+Blocked+in+China/zgg2</link>
            <description>&lt;p&gt;Living in China for the last few months has been surprisingly hassle-free Internet-wise.  In the living room here I&amp;#8217;ve got a 768k &lt;span class=&quot;caps&quot;&gt;DSL&lt;/span&gt; connection, and the government blocking of sites has not been too big of a deal, given that I often don&amp;#8217;t do much more than read &lt;a href=&quot;http://digg.com&quot;&gt;digg.com&lt;/a&gt; or check email.&lt;/p&gt;

The lack of the &lt;a href=&quot;http://bbc.co.uk/2/hi.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;BBC&lt;/span&gt;&lt;/a&gt; has been a bit annoying, but I can get the &lt;a href=&quot;http://nytimes.com&quot;&gt;New York Times&lt;/a&gt; (by changing &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; servers) and &lt;a href=&quot;http://economist.com/index.html&quot;&gt;The Economist&lt;/a&gt; which compensate quite nicely.

	&lt;p&gt;This changed last Thursday when, suddenly, &lt;a href=&quot;http://google.com&quot;&gt;Google&lt;/a&gt; disappeared.  It had worked pretty much flawlessly before that, and &lt;a href=&quot;http://mail.google.com&quot;&gt;Google Mail&lt;/a&gt; was never an issue.&lt;/p&gt;


	&lt;p&gt;There have been periodic outages of sites and things before, but this has been going on for four days now and, more ominously, &lt;a href=&quot;http://google.cn&quot;&gt;google.cn&lt;/a&gt; works perfectly fine.  Perhaps weirdest is that it does work if you keep trying to get to the site.  Having to reload the page 20 times each time you want to check mail is a bit annoying, but better than nothing.&lt;/p&gt;


	&lt;p&gt;Suddenly promoted to the top of the &amp;#8220;To do&amp;#8221; list?  Setting up a &lt;span class=&quot;caps&quot;&gt;VPN&lt;/span&gt; via &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt;.&lt;/p&gt;


	&lt;h3&gt;Hotmail blocked in China&lt;/h3&gt;


	&lt;p&gt;Related to this is that &lt;a href=&quot;http://hotmail.com&quot;&gt;Hotmail&lt;/a&gt; is also proving problematic here in China because of blocking of various stages of Microsoft&amp;#8217;s &lt;a href=&quot;http://live.com&quot;&gt;Microsoft Live&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;A simple workaround for this is to use the mobile phone version of hotmail, which will at least let you check mail.  I just visit the &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;:&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://mobile.msn.com/hm/Folders.aspx&quot;&gt;http://mobile.msn.com/hm/Folders.aspx&lt;/a&gt;&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:43 -0800</pubDate>
        </item>
            
        <item>
            <title>New RSS Feeds</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/New+RSS+Feeds/zgg1</link>
            <description>&lt;p&gt;The &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; feeds on the Chipmunk Ninja site have been changed slightly.  For compatibility, the old &lt;code&gt;rss/tech.rss&lt;/code&gt; and &lt;code&gt;rss/personal.rss&lt;/code&gt; feeds will continue to work, but there are now three new feeds:&lt;/p&gt;


	&lt;table&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;a href=&quot;http://chipmunkninja.com/rss/tech&quot;&gt;rss/tech&lt;/a&gt;&lt;/td&gt;
			&lt;td&gt;Tech Articles&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;a href=&quot;http://chipmunkninja.com/rss/tech&quot;&gt;rss/personal&lt;/a&gt;&lt;/td&gt;
			&lt;td&gt;Personal Articles and Stories&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;a href=&quot;http://chipmunkninja.com/rss/tech&quot;&gt;rss/all&lt;/a&gt;&lt;/td&gt;
			&lt;td&gt;All Chipmunk Ninja Blog Entries&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;




	&lt;p&gt;I have also fixed up the &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; output, particular the &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; headers and the way tags are exposed through the &lt;code&gt;&amp;lt;category&amp;gt;&lt;/code&gt; element.&lt;/p&gt;


	&lt;p&gt;As always, please let me know if there are any problems.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:43 -0800</pubDate>
        </item>
            
        <item>
            <title>Troubles with Asynchronous Ajax Requests and PHP Sessions</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Troubles+with+Asynchronous+Ajax+Requests+and+PHP+Sessions/zggz</link>
            <description>&lt;p&gt;As I sit here watching &amp;#8220;The Muppets Take Manhattan&amp;#8221; in Spanish in the middle of a Costa Rican thunderstorm, I find my mind drifting back to a recent project where I spent a day debugging a frustratingly annoying problem:  A user would visit the web application I was working on, and after a given page was loaded, all of the session data associated with their visit would be suddenly gone.  The user would no longer be logged into the site, and any changes they made (which were logged in session data) were lost.&lt;/p&gt;

I spent tonnes of time in the debugger (while at times unreliable and frustrating on huge projects, the Zend debugger is still an invaluable aid for the &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; application developer) and kept seeing the same thing:  the session data were simply being erased at some point, and the storage in the database would register &amp;#8217;&amp;#8217; as the data for the session.

	&lt;p&gt;It was driving me crazy.  I would sit there in the debugger and go through the same sequence each time:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Debug the request for the page load.&lt;/li&gt;
		&lt;li&gt;Debug the request for the first Ajax request that the page load fired off.&lt;/li&gt;
		&lt;li&gt;Debug the request for the second Ajax request that the page load simultaneously fired off.&lt;/li&gt;
		&lt;li&gt;Debug the request for the third Ajax request that the page initiated&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;In retrospect, looking at the above list, it seems blindingly obvious what I had been running into, but it was very late in a very long contract, and I blame the fatigue for missing what now seems patently obvious:  &lt;a href=&quot;http://en.wikipedia.org/wiki/Race_condition&quot;&gt;A race condition&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;For those unfamiliar with what exactly this is, a race condition is seen most often in applications involving multiple &amp;#8220;threads of execution&amp;#8221; &amp;#8211; which include either separate processes or threads within a process &amp;#8211; when two of these threads (which are theoretically executing at the same time) try to modify the same piece of data.&lt;/p&gt;


	&lt;p&gt;If two threads of execution that are executing more or less simultaneously (but never in exactly the same way, because of &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt; load, other processes, and chance) try to write to the same variable or data storage location, the value of that storage location depends on which thread got there first.  Given that it is impossible to predict which one got there first, you end up not knowing the value of the variable after the threads of execution are finished (in effect, &amp;#8220;the last one to write, wins&amp;#8221;) (see Figure 1).&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;/images/sessionprobs1.png&quot; title=&quot;Racing to destroy values&quot; alt=&quot;Racing to destroy values&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;Normally, when you write web applications in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;, this is really not an issue, as each page request gets their own execution environment, and a user is only visiting one page at a time.  Each page request coming from a particular user arrives more or less sequentially and shares no data with other page requests.&lt;/p&gt;


	&lt;p&gt;Ajax changes all of this, however:  suddenly, one page visit can result in a number of simultaneous requests to the server.  While the separate &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; processes cannot directly share data, a solution with which most &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; programmers are familiar exists to get around this problem:  &lt;a href=&quot;http://www.php.net/manual/en/ref.sessions.php&quot;&gt;Sessions&lt;/a&gt;.  The session data that the various requests want to modify are now susceptible to being overwritten by other ones with bad data after a given request thinks it has written out updated and correct data (See Figure 2).&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;/images/sessionprobs2.png&quot; title=&quot;When requests go bad - clobbering data&quot; alt=&quot;When requests go bad - clobbering data&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;In the web application I was working on, all of the Ajax requests were being routed through the same code that called &lt;code&gt;session_start()&lt;/code&gt; and implicitly &lt;code&gt;session_write_close()&lt;/code&gt; (when &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; ends and there is a running session, this function is called).  One of the Ajax requests would, however, set some session data to help the application &amp;#8220;remember&amp;#8221; which data the user was browsing.  Depending on the order in which the various requests were processed by the server, sometimes those data would overwrite other session data and the user data would be &amp;#8220;forgotten&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;As an example of this problem, consider the following example page, which when fully loaded, will execute two asynchronous Ajax requests to the server.&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
&amp;lt;?php
// race1.php
// part 1
session_start();

//
// We will prime the session data with a simple value here.
// One of the Ajax requests going to race2.php will clobber
// this value periodically.
//
$_SESSION[&#039;fudgecicle&#039;] = &#039;eeeek!&#039;;

?&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Race Condition Demo Page&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;script&amp;gt;
/* part 2 */
/**
 *=-------------------------------------------------------=
 * getNewHTTPObject
 *=-------------------------------------------------------=
 * This function is here just to create a new
 * XmlHttpRequest object.
 */
function getNewHTTPObject()
{
    var xmlhttp;

    /** Special IE only code ... */
    /*@cc_on
      @if (@_jscript_version &amp;gt;= 5)
          try
          {
              xmlhttp = new ActiveXObject(&quot;Msxml2.XMLHTTP&quot;);
          }
          catch (e)
          {
              try
              {
                  xmlhttp = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;);
              }
              catch (E)
              {
                  xmlhttp = false;
              }
         }
      @else
         xmlhttp = false;
    @end @*/

    /** Every other browser on the planet */
    if (!xmlhttp &amp;#38;&amp;#38; typeof XMLHttpRequest != &#039;undefined&#039;)
    {
        try
        {
            xmlhttp = new XMLHttpRequest();
        }
        catch (e)
        {
            xmlhttp = false;
        }
    }

    return xmlhttp;
}

/**
 *=-------------------------------------------------------=
 * onLoadFunction
 *=-------------------------------------------------------=
 * We call this function when the page loads, and it starts
 * two asynchronous Ajax requests to race2.php.
 */
var xml1;
var xml2;
function onLoadFunction()
{
    xml1 = getNewHTTPObject();
    xml2 = getNewHTTPObject();

    xml1.open(&#039;GET&#039;, &#039;http://localhost/race2.php?req1&#039;, true);
    xml2.open(&#039;GET&#039;, &#039;http://localhost/race2.php?req2&#039;, true);

    xml1.onreadystatechange = handleResponse1;
    xml2.onreadystatechange = handleResponse2;

    xml2.send(&#039;&#039;);
    xml1.send(&#039;&#039;);
}

/**
 *=-------------------------------------------------------=
 * handleResponse1
 *=-------------------------------------------------------=
 * This handles the response from the first ajax request.
 * It puts the returned string in the &amp;lt;div&amp;gt; element
 * with th eid &#039;fudgecicles&#039;
 */
function handleResponse1()
{
    if (xml1.readyState == 4)
    {
        document.getElementById(&#039;fudgecicles&#039;).innerHTML =
            xml1.responseText;
    }
}

/**
 *=-------------------------------------------------------=
 * handleResponse2
 *=-------------------------------------------------------=
 * This handles the response from the second ajax request.
 * We don&#039;t actually care about this, so we just ignore
 * the results.
 */
function handleResponse2()
{
    // we don&#039;t care about this response
}
&amp;lt;/script&amp;gt;

&amp;lt;!--
     part 3

     This page just executes the onLoadFunction() call and
     contains a single &amp;lt;div&amp;gt; where the result will be
     placed.
  --&amp;gt;
&amp;lt;body onLoad=&#039;onLoadFunction();&#039;&amp;gt;
  &amp;lt;div id=&#039;fudgecicles&#039;&amp;gt;Waiting for response from Server&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;The code is divided into three main sections:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;The first contains the call to &lt;code&gt;session_start()&lt;/code&gt; and opens the &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; headers.&lt;/li&gt;
		&lt;li&gt;The second contains the Javascript code to execute the asynchronous requests to the server.  The biggest function, &lt;code&gt;getNewHTTPObject()&lt;/code&gt; is used to create new objects.  The &lt;code&gt;onLoadFunction()&lt;/code&gt; is executed when the page finishes loading and starts the ball rolling, while the other two functions are simply used to wait for and handle the responses and results from the asynchronous requests.&lt;/li&gt;
		&lt;li&gt;In the final section, we just write out the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; section of the document, which contains a single &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element to hold the results and an attribute on the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; element to make sure that the &lt;code&gt;onLoadFunction()&lt;/code&gt; is called when the document finishes loading.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;The asynchronous Ajax requests are then made to &lt;i&gt;race2.php&lt;/i&gt; and are processed by the following code, which can handle two different Ajax work requests:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
&amp;lt;?php
// race2.php

session_start();

//
// if they ask for req1, then just return the current value
// of the $_SESSION[&#039;fudgecicles&#039;] data.  If they ask for
// req2, then have this session simulate a bogus value by
//  setting $_SESSION[&#039;fudgecicles&#039;] to &#039;&#039;.
//
// NOTE:  the two for loops are to simulate the various
//        Ajax processes doing lots of stuff, and force
//        the processor to interrupt the processes
//        periodically to let the other work.  This helps
//        the race condition occur more.
//
if (isset($_GET) and isset($_GET[&#039;req1&#039;]))
{
    // waste time
    for ($x = 0; $x &amp;lt; 10000; $x++)
        strpos(&#039;asdfasdf&#039;, &#039;tttttttttttttttasdfioap&#039;);

    if (isset($_SESSION[&#039;fudgecicle&#039;])
        and $_SESSION[&#039;fudgecicle&#039;] != &#039;&#039;)
    {
        $retString = $_SESSION[&#039;fudgecicle&#039;];
    }
    else
        $retString = &#039;(empty)&#039;;
}
else if (isset($_GET) and isset($_GET[&#039;req2&#039;]))
{
    // waste time
    for ($x = 0; $x &amp;lt; 10000; $x++)
        strpos(&#039;asdfasdf&#039;, &#039;tttttttttttttttasdfioap&#039;);

    $retString = &#039;&#039;;
    $_SESSION[&#039;fudgecicle&#039;] = &#039;&#039;;
}

header(&#039;Content-Type: text/plain&#039;);
echo $retString;
?&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;This &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; script handles the two request types differently, and creates the race condition by having the second request type &lt;i&gt;req1&lt;/i&gt; set the sesion data to &amp;#8217;&amp;#8217;.  (In a real world application, you might have accidentally had this request set some value you thought was meaningful).&lt;/p&gt;


	&lt;p&gt;If you install the two files &lt;i&gt;race1.php&lt;/i&gt; and &lt;i&gt;race2.php&lt;/i&gt; on your server, and then load &lt;i&gt;race1.php&lt;/i&gt; into your borwser, you will periodically see that the test string is set after the page is completely loaded, and other times it will be &amp;#8220;(empty)&amp;#8221;, indicating that the second Ajax request has clobbered the value.&lt;/p&gt;


	&lt;p&gt;Now that we are aware of this problem and how it can manifest itself, the next question is, of course, how do we solve it?  Unfortunately, I think this is one of those problems best solved by avoiding it.  Building in logic and other things into our web application to lock the threads of execution (i.e. individual requests) would be prohibitively expensive and eliminate much of the fun and many of the benefits of asynchronous requests via Ajax.   Instead, we will avoid modifying session data when we are executing &lt;i&gt;multiple&lt;/i&gt; session requests.&lt;/p&gt;


	&lt;p&gt;Please note that this is much more specific than saying simply that we will avoid modifying session data during any Ajax request.  Indeed, this would be a disaster:  In a Web 2.0 application, we are mostly likely using Ajax for form submission and updating the state of the user data (i.e. session data) as the data are processed and we are responding to the changes.  However, for those requests we are using to update parts of pages dynamically, we should be careful to avoid modifying the session data in these, or at least do so in a way that none of the &lt;i&gt;other&lt;/i&gt; requests are going to see changes in their results depending on these session data.&lt;/p&gt;


	&lt;p&gt;Ajax requests and session data do not have be problematic when used together:  With a little bit of care and attention, we can write web applications that are powerful, dynamic, and not plagued by race condition-type bugs.&lt;/p&gt;


	&lt;p&gt;Got other suggestions or solutions to this problem?  Add a comment or mail me, and I&amp;#8217;ll update the article.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:42 -0800</pubDate>
        </item>
            
        <item>
            <title>PHP Book Addenda I</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/PHP+Book+Addenda+I/zggx</link>
            <description>&lt;p&gt;As I sat down to edit &amp;#8220;Core Web Application Programming with &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; and MySQL&amp;#8221;, I would sometimes find errors in the text so blindingly obvious and stupid that I would question whether or not I was truly qualified to write such a book.  And yet, after talking with some other people who write books (and recalling days when I wrote huge amounts of code), it seems that this is all common and with much proof-reading and the hard work of some friendly reviewers, I was able to write a book of extremely high quality.&lt;/p&gt;


	&lt;p&gt;Of course, that just meant I would be even more devastated when the first technical errors &lt;span class=&quot;caps&quot;&gt;WERE&lt;/span&gt; found in the book.&lt;/p&gt;


	&lt;p&gt;There have been a couple, but they&amp;#8217;re not that killer serious.&lt;/p&gt;


	&lt;h3&gt;Chapter 21 Error&lt;/h3&gt;


	&lt;p&gt;In Chapter 21, where the book discusses writing your own output handler, the constant in the &lt;code&gt;$_SESSION&lt;/code&gt; array to check is &lt;code&gt;HTTP_ACCEPT_ENCODING&lt;/code&gt;, without the letter &amp;#8216;S&amp;#8217; on the word accept.&lt;/p&gt;


	&lt;h3&gt;The Accompanying Source Code&lt;/h3&gt;


	&lt;p&gt;There are a couple of errors in the source code, the most glaring of which &lt;span class=&quot;caps&quot;&gt;DID&lt;/span&gt; get fixed, but never made it on to the shipping &lt;span class=&quot;caps&quot;&gt;CD ROM&lt;/span&gt; (d&amp;#8217;oh!).  In the &lt;i&gt;SimpleBlog&lt;/i&gt; sample, in the file &lt;i&gt;lib/entrymanager.inc&lt;/i&gt;, the class &lt;code&gt;DBManager&lt;/code&gt; is accidentally misspelled &lt;code&gt;DBMananager&lt;/code&gt;.  Just fix it and change it back to the correct spelling and the sample will compile fine under &lt;span class=&quot;caps&quot;&gt;PHP 5&lt;/span&gt;.0.x (x &amp;lt;= 4).&lt;/p&gt;


	&lt;p&gt;The other problem with the samples is that some new things have appeared in newer versions of &lt;span class=&quot;caps&quot;&gt;PHP 5&lt;/span&gt;.0.y (y &amp;gt;= 5).  &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; now defines a class called &lt;code&gt;InvalidArgumentException&lt;/code&gt;, which conflicts directly with the class I have defined using the same name.  The easy fix for this problem is to simply change the name of the class slightly, to something like &lt;code&gt;MyInvalidArgumentException&lt;/code&gt; or some such thing.&lt;/p&gt;


	&lt;p&gt;To save you the hassle of tracking down and fixing all of these problems, I have put a new copy of the book source code up on the &lt;i&gt;chipmunkninja.com&lt;/i&gt; servers.  You can download these from here:
&lt;a href=&quot;http://www.chipmunkninja.com/download/phpwasrcupdate_2005-12-01.zip&quot;&gt;phpwasrcupdate_2005-12-01.zip&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;As always, if you see any other problems or errors in the book, or just want to comment on it, please feel free to &lt;a href=&quot;mailtomarcwan&amp;#64;chipmunkninja&amp;#46;com&quot;&gt;drop me some mail&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;I remain chagrined, but I&amp;#8217;ll get over it.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:42 -0800</pubDate>
        </item>
            
        <item>
            <title>The Best Game You&#039;re not Playing</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/The+Best+Game+You%27re+not+Playing/zggw</link>
            <description>&lt;p&gt;You turn the corner, walk to the end of the hall, and open the door.  Inside, a giant orange &amp;#8220;D&amp;#8221; rears its ugly head to attack.  You panic and kick the dog! (Argh! You didn&amp;#8217;t mean to do that!) It yelps at you, but still attacks the dastardly beast on your behalf.  Your sword is useless, and you are gravely wounded.&lt;/p&gt;


	&lt;p&gt;You have only one option left &amp;#8211; that scroll that you found lying in the pile of dust in that last room.  You&amp;#8217;re not sure what it is, but you&amp;#8217;re running out of time and it may just save your neck.  You read it and &amp;#8230;&lt;/p&gt;


	&lt;p&gt;All your armour falls off and turns into dust.  The orange &amp;#8220;D&amp;#8221; proceeds to eat you for breakfast.  Game over.&lt;/p&gt;

Welcome to another average game of the best game you&amp;#8217;re not playing:  Nethack.  Inspired by an earlier similar game called Rogue, Nethack has been an active project for over 20 years, being worked on by some well known names such as Jay Fenlason and Jon Payne.

	&lt;p&gt;One of the biggest reasons you&amp;#8217;re probably not playing it?  It&amp;#8217;s entirely &lt;span class=&quot;caps&quot;&gt;ASCII&lt;/span&gt; based.  You are a small &amp;#8221;@&amp;#8221; character (assuming you&amp;#8217;re humanoid) fighting off little &amp;#8220;d&amp;#8221;s (dogs and jackals), &amp;#8220;o&amp;#8221;s (goblins, orcs, and Uruk-Hai), and &amp;#8220;D&amp;#8221;s (dragons), oh my!.  Walls are made with plain old |, -, and + &lt;span class=&quot;caps&quot;&gt;ASCII&lt;/span&gt; characters, and you use the cursor keys to move around in the dungeon.  Only on some platforms, such as Microsoft Windows, do you even know you&amp;#8217;re fighting a brown &amp;#8220;c&amp;#8221; (coatl &amp;#8211; tough, but survivable) versus a yellow &amp;#8220;c&amp;#8221; (a cicatrice &amp;#8211; bad, bad, and more bad).&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;/images/nethack1.jpg&quot; title=&quot;Nethack - It&#039;s all ASCII baby!&quot; alt=&quot;Nethack - It&#039;s all ASCII baby!&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;The current version is 3.4.3, and supports a remarkably wide variety of platforms and architectures, including Unix, Windows, and my trusty &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;-based powerbook.  The game is controlled by keyboard sequences and are usually single characters, sometimes requiring you to hold down the &lt;span class=&quot;caps&quot;&gt;CTRL&lt;/span&gt; or &lt;span class=&quot;caps&quot;&gt;ALT&lt;/span&gt; keys first.  Thus, instead of having to type &amp;#8220;pick up scroll, pick up potion&amp;#8221;, you can just hit &amp;#8221;,&amp;#8221; and select the items you want to grab.&lt;/p&gt;


	&lt;p&gt;In the game, in a way familiar to anybody who&amp;#8217;s played games like Dungeons &amp;#38; Dragons, you are an adventure-seeking character, working your way down through dungeons, mazes, Gehennom, and various elemental planes, to find the Amulet of Yendor, take it from the body of the Wizard of Yendor, who is not at all inclined to let it go, and carry it out to the real world again.  Along the way, you will have to defeat monsters, the undead, ghosts of players past, and grab as much loot as you can.  More monsters and loot mean more points, which is good.&lt;/p&gt;


	&lt;p&gt;To give the game more variety, you can choose from a number of character types, including wizards, knights, valkyries, samurai, tourists, and barbarians.  These all have various strengths and weaknesses, such as different affinities for magic, healing, fighting, or otherwise doing cool things.  As you use different character types and die (often) and try again, you&amp;#8217;ll learn which ones are better at which things, and how to make the best of all their skills.&lt;/p&gt;


	&lt;p&gt;Most impressive are the dizzying number of different levels and special places this game offers.    You will go through traditional looking dungeon levels, pass through special floors with puzzles and other tricks and traps, and then proceed to other special floors with neat surprises at the end.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;/images/nethack2.jpg&quot; title=&quot;Don&#039;t forget to feed your dog. They get hungry!&quot; alt=&quot;Don&#039;t forget to feed your dog. They get hungry!&quot;/&gt;&lt;/p&gt;


	&lt;p&gt;Make no mistake: the game is hard.  Between random chance and random levels, your game can go south, quickly.   But in those games where you do everything right and things go your way, you can do gloriously well and get tantalisingly far along in the game&amp;#8212;usually only to do something incredibly stupid and kill yourself (I have done this so many times it is embarrassing).&lt;/p&gt;


	&lt;p&gt;All of this combines to make Nethack one of the most replayable games I have ever seen.  I buy other games, play them, and either finish them or get bored of doing the same tedious crap again and again.  I always end up coming back to Nethack, to get my butt kicked.  If you are a hard core pure gamer, you can figure out how the game works by trail and error (and frequently dying).  For those less patient, you can check out the source code (eeek!) or one of the many Nethack Spoilers sites still viewable to this day on the Intarwebs.&lt;/p&gt;


	&lt;p&gt;So before you sit and mock the lowly &lt;span class=&quot;caps&quot;&gt;ASCII&lt;/span&gt; game player from behind your texture mapping 5GHz overclocked-requiring fully light-sourced bouncing bits of anatomy first-person shooter games, give Nethack a try.  I bet you&amp;#8217;ll get hooked.&lt;/p&gt;


	&lt;p&gt;Nethack sources and many binaries are available from the Nethack website, &lt;a href=&quot;http://www.nethack.org&quot;&gt;www.nethack.org&lt;/a&gt;.  The game installs trivially on most supported platform.&lt;/p&gt;</description>
            
            <pubDate>Thu, 01 Mar 2007 19:17:41 -0800</pubDate>
        </item>
            
        <item>
            <title>Finding the Love</title>
            <link>http://swik.net/User:marc/Chipmunk+Ninja+Technical+Articles/Finding+the+Love/zggv</link>
            <description>&lt;p&gt;In March of this year, having largely finished writing &lt;a href=&quot;http://www.phptr.com/bookstore/product.asp?isbn=0131867164&amp;#38;rl=1&quot;&gt;my first book&lt;/a&gt; on web application programming with &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; and MySQL, I realised it was time to find another contract.  I hadn&amp;#8217;t worked in nearly a year, and the reserves were getting a little bit lower than I would normally like.&lt;/p&gt;


	&lt;p&gt;Around then, I started getting a number of emails and phone calls from people interested in having me come work for them for a while.  Most of the jobs were to write some .NET applications or tools, or otherwise C/C++ things related to &lt;span class=&quot;caps&quot;&gt;OLE2&lt;/span&gt;/COM that I did all the time when I worked for Microsoft in the 1990s.  The money for these contracts is usually good, and I was relieved to learn I wasn&amp;#8217;t going to be smashing open the piggy bank for extra funds.&lt;/p&gt;


	&lt;table style=&quot;width: 100%; border: 1px solid black; background: #eeeeee; padding; 5px;&quot;&gt;
		&lt;tr&gt;
			&lt;td&gt;Cool Link #1:   AdiumX, an excellent chat client for &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;.&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;a href=&quot;http://www.adiumx.com&quot;&gt;www.adiumx.com&lt;/a&gt;&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;




	&lt;p&gt;When I went to talk with the various people about the contracts, however, I suddenly found myself extremely unenthused about the work being offered.  None of it sounded terribly difficult, but at the same time, none of it sounded in the least bit interesting.  At all.  Had I completely bottomed out on the whole computer thing?  After six months of full-time writing a book and programming &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; and MySQL, was I so burned out that I needed a break from computing, or worse, a complete change of career?  It certainly felt so.  At the peak (trough?) of my self-doubt, taking a job for pennies above minimum wage at the local café where I get my &lt;a href=&quot;http://www.chipmunkninja.com/article/addiction&quot;&gt;daily fix&lt;/a&gt; sounded more interesting than taking any of the offered jobs.&lt;/p&gt;


	&lt;p&gt;I made a commitment to myself:  no more jobs that sucked.  While I can&amp;#8217;t honestly say that any of the offered jobs were what anybody would call &amp;#8216;terrible work&amp;#8217; &amp;#8211; they pay well and treat me well &amp;#8211;  at the end of the day they just weren&amp;#8217;t any &lt;i&gt;fun&lt;/i&gt;, and I&amp;#8217;ve long espoused that life is too short to do crappy stuff that makes you crabby.  So, I turned all those jobs down and took a job doing some open source work with &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; and MySQL which payed reasonably well, and figured I&amp;#8217;d be fine.&lt;/p&gt;


	&lt;table style=&quot;width: 100%; border: 1px solid black; background: #eeeeee; padding; 5px;&quot;&gt;
		&lt;tr&gt;
			&lt;td&gt;Cool Link #2:   FireFox for &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt;&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;a href=&quot;http://www.mozilla.org/products/firefox&quot;&gt;www.mozilla.org&lt;/a&gt;&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;




	&lt;p&gt;And then I lost my Dell laptop&amp;#8212;it was taken to Europe by Samantha, who was doing a study abroad program in Rome.  I still had some more work to do on my book, and since that absolutely &lt;em&gt;had&lt;/em&gt; to be done at the caf√©, I needed a new laptop.&lt;/p&gt;


	&lt;p&gt;On a whim, I went down to the local Apple Store (Seattle is now swarming with them) and bought a 12&amp;#8221; Powerbook.  I took it home, spent a good half hour trying to get it to find my crappy 64-bit &lt;span class=&quot;caps&quot;&gt;WEP&lt;/span&gt; encoded wireless router (which was so old it&amp;#8217;s a miracle that &lt;em&gt;anybody&lt;/em&gt; finds it) and started playing.&lt;/p&gt;


	&lt;p&gt;In the early 1990s, McGill University&amp;#8217;s School of Computer Science (SOCS) purchased a number of NeXT computers for laboratory use.  They were very cool, if somewhat ahead of their time, and I had heard that the new &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; was based on this, and thus wouldn&amp;#8217;t suck as much as I&amp;#8217;ve always perceived &lt;span class=&quot;caps&quot;&gt;OS 9&lt;/span&gt; and predecessors.  I had also read that &lt;a href=&quot;http://www.freebsd.org&quot;&gt;FreeBSD&lt;/a&gt;, an operating system of which I&amp;#8217;ve long been a fan, would form a key part of the new operating system.&lt;/p&gt;


	&lt;p&gt;I had no idea how cool the new computer would be.  Within the hour, I had the &lt;a href=&quot;http://developer.apple.com/tools/xcode/index.html&quot;&gt;developer tools and compiler&lt;/a&gt; downloaded and was building and installing my favourite software.  &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; appeared to be what I had long dreamed of:  Unix with a non-sucky &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt; on top of it.  I was hooked.&lt;/p&gt;


	&lt;table style=&quot;width: 100%; border: 1px solid black; background: #eeeeee; padding; 5px;&quot;&gt;
		&lt;tr&gt;
			&lt;td&gt;Cool Link #3:   Microsoft Resources for the Mac&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;
&lt;a href=&quot;http://www.microsoft.com/mac&quot;&gt;www.microsoft.com&lt;/a&gt;&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;




	&lt;p&gt;I finished my book on the new machine, and then the ladyfriend came back from Europe, at which point it was deemed that the Dell laptop was dead (or at least really sleepy).  She became the new owner of the 12&amp;#8221; Powerbo