<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Codethink &#187; software</title>
	<atom:link href="https://codethink.no-ip.org/posts/software/feed" rel="self" type="application/rss+xml" />
	<link>https://codethink.no-ip.org</link>
	<description>A blog about coding, life, and other arbitrary topics</description>
	<lastBuildDate>Sun, 15 Mar 2026 21:30:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.29</generator>
	<item>
		<title>And we&#8217;re back&#8230;</title>
		<link>https://codethink.no-ip.org/archives/1690</link>
		<comments>https://codethink.no-ip.org/archives/1690#comments</comments>
		<pubDate>Sat, 03 Jul 2021 05:10:24 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[banter]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[hardware]]></category>
		<category><![CDATA[operating systems]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=1690</guid>
		<description><![CDATA[Some things I&#8217;ve learned recently-ish, over the past couple years or so: Don&#8217;t assume that SSD&#8217;s won&#8217;t/can&#8217;t fail. When buying an SSD, check what controller it uses and then get on Google to see how many data recovery providers claim &#8230; <a href="https://codethink.no-ip.org/archives/1690">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Some things I&#8217;ve learned recently-ish, over the past couple years or so:</p>
<ol>
<li>Don&#8217;t assume that SSD&#8217;s won&#8217;t/can&#8217;t fail.</li>
<li>When buying an SSD, check what controller it uses and then get on Google to see how many data recovery providers claim to support that controller; if you find one or less, buy something else.</li>
<li>Or even better, RAID and/or back up SSD&#8217;s just like you would HDD&#8217;s.</li>
<li>In the event of failure, an idle, unpowered SSD can retain its contents for a year or so at least with no degradation (YMMV/don&#8217;t test this on any data you care about!).</li>
<li>People will eventually figure out how to recover your data, if you give them enough money.</li>
<li>Making a filesystem dump of an old Windows install bootable again is probably easier now than it&#8217;s ever been.</li>
<li>Making an old Windows install (or installer) work with USB3.x and NVMe is nigh impossible.</li>
<li>With enough old hardware, several rounds of &#8220;musical SSD&#8221;, Windows 10 installation media, and sufficient masochism, it can be done.</li>
<li>Manually bootstrapping a GPT partition is also possible.</li>
<li>Not everyone is courteous enough to warn you when they suggest running commands that will immediately and irreversibly remove all partitions from a disk.</li>
<li>Windows no longer seems to care how many times you swap your install between completely different computers.</li>
<li>When USPS says &#8220;7-10 business days&#8221; what they really mean is &#8220;3-4 weeks, if you&#8217;re lucky&#8221;.</li>
</ol>
<p>Anyhow, major props to ACE Data Recovery for figuring out how to restore data from dead Sandforce drives.  And also to Recovery Force, for pointing me in their direction.</p>
<p>Normally scheduled programming of &#8220;mostly nothing much&#8221; should be resuming shortly.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/1690/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Matchbook &#8211; Multi-platform Realtime Gaming</title>
		<link>https://codethink.no-ip.org/archives/1046</link>
		<comments>https://codethink.no-ip.org/archives/1046#comments</comments>
		<pubDate>Sun, 26 Jan 2014 13:56:58 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[objc]]></category>
		<category><![CDATA[open-source]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=1046</guid>
		<description><![CDATA[Have you ever thought that it would be cool if you could build a cross-platform or multi-platform game and connect from one platform to another without having to do all the heavy lifting with respect to matchmaking, communications, and related &#8230; <a href="https://codethink.no-ip.org/archives/1046">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Have you ever thought that it would be cool if you could build a cross-platform or multi-platform game and connect from one platform to another without having to do all the heavy lifting with respect to matchmaking, communications, and related tasks yourself?  Well now you can, thanks to <a href="https://github.com/adam-roth/matchbook" target="_blank">Matchbook</a>.</p>
<div id="attachment_1049" style="width: 650px" class="wp-caption aligncenter"><a href="http://codethink.no-ip.org/wordpress/wp-content/uploads/2014/01/running_small.jpg" rel="lightbox[1046]"><img src="http://codethink.no-ip.org/wordpress/wp-content/uploads/2014/01/running-1200x721.jpg" alt="Matchbook Example &quot;Game&quot;" title="Matchbook Example &quot;Game&quot;" width="640" height="384" class="size-large wp-image-1049" /></a><p class="wp-caption-text">Matchbook Example &quot;Game&quot;, 2x iOS and 2x Android clients</p></div>
<p>Matchbook is a lightweight and platform-agnostic matchmaking solution, intended for use in mobile applications (think games that require near-real-time, relatively-low-latency, persistent communications between two or more client devices).</p>
<p>At its core is a server component, which provides a JSON-based webservice allowing clients to find, create, and join matches. The server also acts as a proxy/relay when necessary, allowing client devices to tunnel through any firewalls that might exist between them.</p>
<p>In addition to the server component, Matchbook includes prebuilt SDK&#8217;s for both Java and Objective-C. These SDK&#8217;s are intended to support the development of native applications that make use of the Matchbook webservice on Android and iOS devices, respectively.</p>
<p>I could go on at length, but it&#8217;s simpler to just link to the project on Github (Matchbook is open-source, and permissively licensed, naturally):</p>
<p><a href="https://github.com/adam-roth/matchbook" target="_blank">https://github.com/adam-roth/matchbook</a></p>
<p>Note that Google is currently building comparable functionality into Google Play, although their realtime communications API is currently only available on Android (iOS support is under development).  </p>
<p>And although Apple already has realtime and turn-based gaming API&#8217;s for iOS, they natually have no intention of inviting Android devices to the party.  Ever.</p>
<p>So let the record show that Matchbook got there first.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/1046/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[iOS] Jira Mobile Connect</title>
		<link>https://codethink.no-ip.org/archives/788</link>
		<comments>https://codethink.no-ip.org/archives/788#comments</comments>
		<pubDate>Fri, 04 Nov 2011 06:48:08 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[banter]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[jira]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=788</guid>
		<description><![CDATA[Not long ago Atlassian released version 1.0 (now up to 1.0.7) of their Jira Mobile Connect plugin. This is a plugin for Jira (obviously) that aims to simplify testing, error-reporting, and feedback collection/management for iOS applications. Assuming that you are &#8230; <a href="https://codethink.no-ip.org/archives/788">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Not long ago Atlassian released version 1.0 (now up to 1.0.7) of their <a href="https://plugins.atlassian.com/plugin/details/322837" target="_blank">Jira Mobile Connect plugin</a>.  This is a plugin for Jira (obviously) that aims to simplify testing, error-reporting, and feedback collection/management for iOS applications.  Assuming that you are doing iOS software development and have a Jira server instance running (which you really should if you are doing any nontrivial amount of development work of any variety) then using this plugin in your apps is really a no-brainer.  Jira Mobile Connect includes a number of very cool features, such as the ability for users to attach annotated screenshots/images to their feedback reports, to record audio to attach with their feedback, and even to chat back and forth with the developer(s) working on their issue/ticket .  And of course it does basic crash logging and reporting, as well. </p>
<p>Previously if you wanted a free/open-source crash reporting framework for iOS your options were basically limited to <a href="http://quincykit.net/server.html" target="_blank">QuincyKit</a>, which is a serviceable but basic solution.  Sadly, the backing architecture used by the QuincyKit server is not well designed and scales very poorly with the number of crash reports in the system.  Once you have around 5,000 you&#8217;ll notice the server slowing down significantly, and go much beyond 10,000 that and the system grinds to an unusable halt.  With a day or so of database and code refactoring, these scalability issues can be resolved, creating a system performant enough to track millions of error logs or more.  But that&#8217;s a subject for another time.  The point for today is that despite its basic level of functionality and flawed server architecture, there are a few key areas in which QuincyKit blows the default implementation of Jira Mobile Connect out of the water:</p>
<ol>
<li>Automatic grouping of crash reports.</li>
<li>Automatic symbolication of error logs.</li>
</ol>
<p>If you have any experience whatsoever with supporting multiple high-volume iOS applications you will instantly realize that these are features that you want.  They might even be features that you want more than annotated screenshots, audio feedback, user chat, or seamless integration with Jira and all the awesomeness that Jira brings.  In short, Jira Mobile Connect&#8217;s lack of support for these two key features may cause serious developers to pass it over in favor of other solutions.  </p>
<p>Without grouping every single crash will be creating a new ticket in Jira that you need to track and resolve.  Multiple instances of the same crash will have to be manually flagged as duplicates within Jira.  And without symbolication trying to actually map back from an error log to the line of code that caused it is an exercise in futility, or at best, tedium.</p>
<p>In any case, rather than abandon the excellent potential shown by Jira Mobile Connect I decided that instead I would attempt to patch it up and add the missing features myself.  It&#8217;s all open-source code, after-all, and if the tangled mess of PHP that is QuincyKit server can provide these features then they can&#8217;t be that difficult to implement.  Unfortunately I had to change too many files in too many different places to show the code here, but if you want the short version of it I was able to implement both grouping and symbolication, and you&#8217;re welcome to view the complete diffs on bitbucket:</p>
<p><a href="https://bitbucket.org/aroth_iapps/jiraconnect-ios-iapps/compare/..atlassian/jiraconnect-ios" target="_blank">https://bitbucket.org/aroth_iapps/jiraconnect-ios-iapps/compare/..atlassian/jiraconnect-ios</a> (client/native iOS code)<br />
<a href="https://bitbucket.org/aroth_iapps/jiraconnect-jiraplugin-iapps/compare/..atlassian/jiraconnect-jiraplugin" target="_blank">https://bitbucket.org/aroth_iapps/jiraconnect-jiraplugin-iapps/compare/..atlassian/jiraconnect-jiraplugin</a> (server/Java code)</p>
<p>One interesting side-effect of adding groups was that it became possible for multiple client UID&#8217;s to be associated with a single Jira ticket.  This had an important implication for feedback notifications/chat in that the reference implementation allowed only a single UID to be associated with each Jira ticket.  Since the UID is used for determining what notifications/updates to send to the native client, this restricted update notifications to a single user per ticket.  Not too useful if you have a common crash that thousands of users have experienced.  The implementation above extends the data model to allow multiple UID&#8217;s to be stored against a single Jira ticket, allowing each UID to be updated when new feedback is posted by the developer on a ticket.  In essence, implementing grouping also required the implementation of group feedback/chat.</p>
<p>There is one caveat with my server implementation, in that it assumes the existence of the &#8216;<em>symbolicatecrash</em>&#8216; utility on the system&#8217;s runtime <em>PATH</em>.  This means that it will only work if your Jira server is hosted on a Mac, with the proper XCode developer tools installed (and with your application&#8217;s .app and .dSYM files copied to the local filesystem).  This is of course a requirement regardless if you want automatic symbolication to work on any sort of system; somewhere there needs to be a Mac with &#8216;<em>symbolicatecrash</em>&#8216; available.  In any case, it is a fairly simple matter to either turn this off or otherwise make it more intelligent, if your Jira server is incapable of running &#8216;<em>symbolicatecrash</em>&#8216;.</p>
<p>Also note that the native iOS code has been restructured to build a universal iOS framework as opposed to an architecture-specific static library.  This is done using Karl Stenerud&#8217;s excellent <a href="https://github.com/kstenerud/iOS-Universal-Framework" target="_blank">XCode4 Project Template</a>.  You will need to install this template in order to actually build the modified code.  Or you can just refactor it back to build a static library again, but why would you want to do that?</p>
<p>When using the iOS framework, be aware that you will need to set the &#8216;-<em>all_load</em>&#8216; linker flag and also include all the images and nibs in the framework&#8217;s &#8216;<em>/Resources</em>&#8216; folder as part of your build.  You will probably also want to include the &#8216;<em>JMCLocalizable.strings</em>&#8216; file in the same folder as well, to provide proper text and labels on Jira Mobile Connect&#8217;s UI elements.</p>
<p>Regardless, if you do a lot of iOS development and are already using Jira (like you should be) then I encourage you to check this out.  This is the Jira Mobile Connect plugin, now with automatic grouping and error log symbolication.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/788/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Natural Scrolling Isn&#8217;t</title>
		<link>https://codethink.no-ip.org/archives/736</link>
		<comments>https://codethink.no-ip.org/archives/736#comments</comments>
		<pubDate>Sat, 23 Jul 2011 07:50:05 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[banter]]></category>
		<category><![CDATA[operating systems]]></category>
		<category><![CDATA[lion]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[scrolling]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=736</guid>
		<description><![CDATA[Mac users and other developers such as myself who have no choice but to use a Mac for certain projects will already know what I&#8217;m talking about. For everyone else, however, the newest version of OS X includes a most &#8230; <a href="https://codethink.no-ip.org/archives/736">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Mac users and other developers such as myself who have no choice but to use a Mac for certain projects will already know what I&#8217;m talking about.  For everyone else, however, the <a href="http://en.wikipedia.org/wiki/Mac_OS_X_Lion" target="_blank">newest version of OS X</a> includes a most bizarre feature, called &#8220;natural scrolling&#8221;.  Despite its innocuous-sounding name, this feature (which ships enabled by default) breaks the interface to the OS by inverting the direction content scrolls when using the mouse-wheel.  </p>
<p>Apple&#8217;s explanation (and seemingly, justification) for this atrocity of a feature is that &#8220;content should move in the same directions as your finger&#8221;.  Now that&#8217;s all well and good, except for one thing; <em>there is no &#8220;finger&#8221; when using a mouse</em>.  Touch- and mouse-driven are distinct input paradigms.  </p>
<p>Apple is correct in that in a touch-driven system content should indeed track in the same direction as the user&#8217;s finger moves.  If a hypothetical touch-based interface were ever released which scrolled content in the opposite direction of the user&#8217;s finger, then people would say that it was broken.  And rightly so.  Moving content in the same direction as the touch is the intuitive operating mode of a touch interface.</p>
<p>Similarly, moving content in the opposite direction of the scroll (or more accurately, moving the scrollbar in the direction of the scroll) is the intuitive operating mode for a mouse-driven interface.  And it follows that Apple&#8217;s mouse-driven interface in Lion is just as broken as that hypothetical touch-driven interface would be.  By Apple&#8217;s logic scrollbars themselves should also be inverted, tracking from the bottom of the scrollbar to the top as the content scrolls from top to bottom.  Confused yet?  Apple&#8217;s blunder here is that they have conflated mouse-driven input with touch-driven input, without bothering to translate properly between the two.  </p>
<p>As an interesting aside, a comparable analog to touch-style scrolling does exist in the mouse-driven paradigm; the drag operation.  You&#8217;ve probably seen it in things like Adobe PDF documents, and it can also be observed on any scrollbar. In the drag operation you choose an anchor-point, and then that anchor point moves in the same direction that you move, and it all intuitively makes sense. The problem with scrolling using a scroll-wheel is that it has no anchor point from the user&#8217;s point of view (they have done nothing to nominate one, and the UI does nothing to indicate that one has been chosen).  In the mouse-driven paradigm, scrolling is a distinct operation from dragging, and by conflating the two Apple has broken their interface.  At least until they start incorporating a touch-screen into every computer they sell.</p>
<p>If Apple&#8217;s position is to be taken seriously, then we must accept that the current cursor position must always represent where the user&#8217;s &#8220;finger&#8221; is.  There&#8217;s one major problem with that, however.  With a mouse and cursor, the cursor never leaves the screen.  And if the user&#8217;s finger is in constant contact with the screen, then why should there be a separate scroll operation at all?  It would logically follow (since mouse-driven == touch-driven and cursor == finger in Apple&#8217;s world) that since a touch-point exists, and since it is moving, the content (all of it, everywhere) should simply scroll whenever I move the mouse (all the time, everywhere).  But of course that is nonsense, and so is Apple&#8217;s &#8220;natural scrolling&#8221; mouse behavior.  The mouse cursor is not a finger, it does not represent a finger, and its location is not where your finger is touching.  Mouse-driven and touch-driven are different modes of operation, with different intuitive behaviors.</p>
<p>Thankfully, you can <a href="http://www.pcworld.com/businesscenter/article/236182/revert_os_x_lions_page_scrolling_to_the_old_direction.html" target="_blank">turn off &#8220;natural&#8221; scrolling</a> and rid your OS of its nonsense.  I&#8217;ll be happy to turn it back on when my mouse is replaced with a touch-screen display, but until that day comes you can forget about it.  Apple, please stop trying to convince me that moving my mouse cursor around the screen is supposed to be the same thing as dragging my finger all over a touch screen.  It isn&#8217;t, and I&#8217;m not stupid enough to be convinced that it is.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/736/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[Java] URL Rewriting on Tomcat (or any other servlet container)</title>
		<link>https://codethink.no-ip.org/archives/654</link>
		<comments>https://codethink.no-ip.org/archives/654#comments</comments>
		<pubDate>Tue, 07 Jun 2011 11:51:31 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[servlet]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[url-rewrite]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=654</guid>
		<description><![CDATA[Here is a very nice little utility I found recently on an unfortunately very difficult to navigate website. In case it&#8217;s not immediately apparent from that site what I am referring to, I&#8217;m talking about the &#8216;UrlRewriteFilter&#8216; utility featured near &#8230; <a href="https://codethink.no-ip.org/archives/654">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here is a very nice little utility I found recently on an unfortunately very <a href="http://www.tuckey.org/" target="_blank">difficult to navigate website</a>.  In case it&#8217;s not immediately apparent from that site what I am referring to, I&#8217;m talking about the &#8216;<em>UrlRewriteFilter</em>&#8216; utility featured near the top of the page.  This handy Filter implementation allows you to configure <a href="http://httpd.apache.org/docs/current/mod/mod_rewrite.html" target="_blank">mod_rewrite</a> style URL rewriting rules for your J2EE webapp.  If you are having trouble navigating the official site, you can use this <a href="http://urlrewritefilter.googlecode.com/files/urlrewritefilter-3.2.0.zip">direct link</a> to download &#8216;<em>UrlRewriteFilter</em>&#8216; version 3.2.</p>
<p>Sadly, apart from being difficult to navigate, some of the information on the official &#8216;<em>UrlRewriteFilter</em>&#8216; website pertaining to setup and usage of the filter is also incorrect/out of date.  This is really quite a shame, because &#8216;<em>UrlRewriteFilter</em>&#8216; is an excellent little utility and I&#8217;m quite tired of seeing people needlessly running multi-server configurations (typically <a href="http://httpd.apache.org/" target="_blank">Apache httpd</a> for static content, and something like Tomcat, Resin, Jetty, etc. for dynamic content) out of a desire to use this-or-that particular module that only works with httpd or (even worse) out of the outdated and no-longer-relevant notion that servlet containers cannot efficiently serve static content.  So in an effort to save &#8216;<em>UrlRewriteFilter</em>&#8216; from obscurity and an undeserved death at the hands of poor documentation and a shoddy distribution site, here is a complete set of instructions for getting the filter to work in your webapp.</p>
<p>First, you will need to ensure that the &#8216;<em>UrlRewriteFilter</em>&#8216; JAR file is on your web-application&#8217;s classpath.  How you do this will depend upon your build process/how you are constructing your webapp(s), but long story short placing the JAR file in your webapp under &#8216;/WEB-INF/lib&#8217; will do the trick, and if you&#8217;ve spent any time at all working with webapps you probably already have a preferred way of doing this.  Alternately, you may want to install the JAR file in your servlet container&#8217;s &#8216;/lib&#8217; folder, particularly if you are deploying multiple webapps on your server and you want to have &#8216;<em>UrlRewriteFilter</em>&#8216; available to any/all of them automatically.</p>
<p>In any case, once you have the &#8216;<em>UrlRewriteFilter</em>&#8216; JAR on your webapp&#8217;s classpath, the real setup can begin.  Open your application&#8217;s &#8216;<em>web.xml</em>&#8216; file, and add the following filter configuration to your webapp:</p>
<pre class="brush: xml; title: ; notranslate">&lt;!-- URL rewriting --&gt;
&lt;filter&gt;
    	&lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;
      	&lt;filter-class&gt;org.tuckey.web.filters.urlrewrite.UrlRewriteFilter&lt;/filter-class&gt;
      	&lt;init-param&gt;
        	&lt;param-name&gt;logLevel&lt;/param-name&gt;
        	&lt;param-value&gt;WARN&lt;/param-value&gt;
        &lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
    	&lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;
    	&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;</pre>
<p>This instructs the servlet container to route every request that the server receives through the &#8216;<em>UrlRewriteFilter</em>&#8216;.  Note that although it is not discussed on the official site, that &#8216;<em>logLevel</em>&#8216; parameter is absolutely essential.  If you omit it, the filter will fail to initialize properly and yield some very bizarre behavior.  </p>
<p>Anyways, once your &#8216;<em>web.xml</em>&#8216; has been updated, the final step is to add a &#8216;<em>urlrewrite.xml</em>&#8216; file in the same directory as your &#8216;<em>web.xml</em>&#8216; file, and configure it to your liking.  Here is an example &#8216;<em>urlrewrite.xml</em>&#8216; file with a couple basic rewrite rules:</p>
<pre class="brush: xml; title: ; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;!DOCTYPE urlrewrite PUBLIC &quot;-//tuckey.org//DTD UrlRewrite 3.2//EN&quot;
        &quot;http://tuckey.org/res/dtds/urlrewrite3.2.dtd&quot;&gt;
&lt;urlrewrite&gt;
    &lt;!-- user-account activation link --&gt;
    &lt;rule&gt;
    	&lt;from&gt;/activate/([a-f0-9]+)?(.*)&lt;/from&gt;
     	&lt;to&gt;/userController?action=activateUser&amp;amp;token=$1&amp;amp;$2&lt;/to&gt;
    &lt;/rule&gt;

    &lt;!-- default rules included with urlrewrite --&gt;
    &lt;rule&gt;
        &lt;note&gt;
            The rule means that requests to /test/status/ will be redirected to /rewrite-status
            the url will be rewritten.
        &lt;/note&gt;
        &lt;from&gt;/test/status/&lt;/from&gt;
        &lt;to type=&quot;redirect&quot;&gt;%{context-path}/rewrite-status&lt;/to&gt;
    &lt;/rule&gt;
    &lt;outbound-rule&gt;
        &lt;note&gt;
            The outbound-rule specifies that when response.encodeURL is called (if you are using JSTL c:url)
            the url /rewrite-status will be rewritten to /test/status/.

            The above rule and this outbound-rule means that end users should never see the
            url /rewrite-status only /test/status/ both in thier location bar and in hyperlinks
            in your pages.
        &lt;/note&gt;
        &lt;from&gt;/rewrite-status&lt;/from&gt;
        &lt;to&gt;/test/status/&lt;/to&gt;
    &lt;/outbound-rule&gt; 
&lt;/urlrewrite&gt;</pre>
<p>This defines two rules.  The first simply rewrites URL&#8217;s of the form &#8216;<em>/activate/######?[params]</em>&#8216; to something like &#8216;<em>/userController?action=activateUser&#038;token=######&#038;[params]</em>&#8216;, and the second is the default example rule that comes with &#8216;<em>UrlRewriteFilter</em>&#8216; and allows you to see a basic diagnostic page by pointing your browser at &#8216;<em>[your server]/test/status</em>&#8216;.  </p>
<p>And there you have it.  Quite simple, really, and now there&#8217;s one less reason to continue running two distinct server instances where one would do just as well.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/654/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Portal 2</title>
		<link>https://codethink.no-ip.org/archives/578</link>
		<comments>https://codethink.no-ip.org/archives/578#comments</comments>
		<pubDate>Sat, 23 Apr 2011 12:26:34 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[gaming]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[portal]]></category>
		<category><![CDATA[review]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=578</guid>
		<description><![CDATA[For anyone that hasn&#8217;t noticed, Portal 2 was released a few days ago. I&#8217;ve already played through the single-player portion of the game (the only portion that I&#8217;m interested in, to be honest), and thought I would write up a &#8230; <a href="https://codethink.no-ip.org/archives/578">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>For anyone that hasn&#8217;t noticed, <a href="http://en.wikipedia.org/wiki/Portal_2" target="_blank">Portal 2</a> was released a few days ago.  I&#8217;ve already played through the single-player portion of the game (the only portion that I&#8217;m interested in, to be honest), and thought I would write up a review.  </p>
<p>Long story short, my feelings toward Portal 2 are a bit mixed.  Viewed as a game in its own right, Portal 2 does not disappoint.  It&#8217;s really hard to find much to fault it for in this context.  But viewed as a continuation of the original Portal, the game just doesn&#8217;t quite live up to the sky-high expectations that I (and probably other fans of the original game) had for it.  GLaDOS is back, and just as sarcastic, humorous, and passive-aggressive as ever.  At least for the first half of the game.  Something seems to happen to the writing about halfway through; it loses its clever wit, that special something-or-other that left you anticipating the next catty remark from GLaDOS and laughing-out-loud when it finally arrived.  </p>
<p>Much of the dialog towards the end of the game becomes just matter-of-fact moving-the-story-along chatter, with one AI acting loopy and another AI trying to provide a plausible explanation for why the first one is acting loopy.  After a certain point, it just doesn&#8217;t feel as clever.  At first I thought that it might be just because your antagonist changes, but that&#8217;s not really it.  Wheatley&#8217;s early game dialog is on par with anything GLaDOS ever said, but as the game progresses his lines become less and less inspired.  By the time you reach the end some of them are so bland that you pretty much have to force yourself to listen.</p>
<p>In the end, I think the developers erred in putting too much effort into trying to explain and justify their game world.  Why should I care about history when there is a sarcastic, witty, and antagonistic AI practically goading me into dismantling it?  Such was the case in Portal, but unfortunately not so in Portal 2.  Instead the game distracts itself in trying to explain the origins of its world and the players within it, and the result is that some of the drive to keep pushing forward is lost.</p>
<p>Moving along, Portal had its fair share of fiendishly difficult levels.  Levels which would leave you genuinely stumped and probably kill you once or twice before you puzzled your way out of them.  Portal 2 has a couple of moderately challenging levels, but for the most part the puzzles are straightforward and easy to solve.  I&#8217;m glad that for the most part the developers fixed it so that going through a portal won&#8217;t arbitrarily rotate your character&#8217;s orientation (and/or they made it easier to avoid placing portals such that they force you to rotate), but apart from that I think the game was nerfed a bit too much.  </p>
<p>Portal put you on a conveyor belt heading towards an incinerator and left you with very little time to work out an escape plan.  The situation felt very tense the first time through, and if you did not react very quickly to locate the way out then the game had no qualms about killing you for your shortcoming.  Portal 2 has a similar scenario, but the way out of it is much too obvious and the element of danger just isn&#8217;t there.  Rather than being compelled to react, it feels like there&#8217;s plenty of time to just stand their and listen to the AI gloat about its triumph.  The sense of imminent danger just isn&#8217;t there like it was in the original game.</p>
<p>That said, there&#8217;s very little to complain about in terms of graphics, sound or gameplay.  Any reviewer who gripes about Portal 2 (PC version, obviously) suffering from being a &#8220;port of the console version&#8221; is just being a fool.  Portal 2 was implemented using the Source engine, an engine which began its life first and foremost as a PC game engine.  It cannot be a &#8220;port&#8221; of anything if its implementation engine natively supports the PC as a target platform.  </p>
<p>Yes the graphics in Portal 2 are a bit simple/dated-looking, but such has been the case with every Source-engine game released (even the very first games to use the engine).  Valve has always favored attaining playable framerates on lower-end hardware over throwing in lots of hardware-crushing eye-candy, and I&#8217;m not about to fault them for their decision.  If you need hardware-crushing eye-candy, play Crysis.</p>
<p>On top of its solid graphics and gameplay, Portal 2 gives you quite a few new puzzles to play through.  In fact, there are almost certainly more puzzles in the Portal 2 single-player game than in Portal&#8217;s single-player game.  But, because of the decreased level of difficulty, most of these new puzzles can be breezed through in a handful of minutes, even on your first play-through.  It took me less then 7 hours to complete the single-player game, and I wasn&#8217;t rushing or trying to solve puzzles as quickly as possible.  </p>
<p>I spent time exploring the environment and looking around, trying to knock off as many achievements as I could, and still I only needed 7 hours to complete the game.  That&#8217;s a bit short, but the problem isn&#8217;t that the game itself is too short, rather it&#8217;s that the level of difficulty has been reduced too much.  Once you know the solutions, Portal can be completed in far less than 7 hours.  Portal 2&#8217;s real problem is that too many of the solutions are a bit too obvious.</p>
<p>Portal 2 does introduce a number of new gameplay elements, from the propulsion/repulsion/conversion gels, to mirrored &#8220;discouragement redirection cubes&#8221;, to hard-light bridges, excursion beams, and &#8220;aerial faith-plates&#8221;.  The last of these I find a bit questionable, as their real purpose seems to be replacing some of Portal&#8217;s more challenging jumps (the ones where you have to work out some way to build sufficient momentum to bridge an impassable chasm of some sort or another) with a prepackaged solution that &#8220;just works&#8221;.  </p>
<p>Unlike the gels, mirrors, bridges, and beams, the aerial faith-plates function less as a tool for solving the current puzzle and more like a quick way of hopping between Point A and Point B without using a portal and without having to worry about where you land.  I think the game could have been better without them, but apart from that I also think that the rest of the new gameplay elements function very well within the context of the game, and I&#8217;m surprised that Valve was able to come up with so many new physics things to add to the game.</p>
<p>One last thing that leaves me a little confused is the decision to replace the guided missiles of Portal with generic unpropelled exploding boxes in Portal 2.  It doesn&#8217;t really change the gameplay that much, but personally I found the missiles to be a lot more threatening and fun than some nondescript red boxes that just happen to explode when they hit something.  Perhaps Valve decided that they didn&#8217;t want to renew their missile targeting AI license?</p>
<p>Anyways, though I have picked the game apart over a few minor issues, I still think that overall Portal 2 is a very fun game and worth a play-through or two.  Play it and enjoy it as a game in its own right, as its biggest flaws only become apparent when you hold it to the candle that is Portal the first.  It doesn&#8217;t quite satisfy as a sequel to that original magical title, but as a first-person puzzle game with a completely unique mode of gameplay there&#8217;s still nothing else quite like it.  </p>
<p><strong>Overall score:  8.5 / 10.0</strong></p>
<p>P.S.  The Portal Song is an order of magnitude better than The Portal 2 Song.  So don&#8217;t get your hopes up expecting an epic musical ending like in the first game.  You still get a musical ending, but it&#8217;s not quite as epic.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/578/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing Webcomix</title>
		<link>https://codethink.no-ip.org/archives/511</link>
		<comments>https://codethink.no-ip.org/archives/511#comments</comments>
		<pubDate>Sat, 19 Mar 2011 07:15:12 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[banter]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[media]]></category>
		<category><![CDATA[random]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=511</guid>
		<description><![CDATA[I wanted to take a brief moment to invite anyone who stumbles across this post to beta-test my latest personal project; Webcomix. Webcomix is a simple web-comic aggregation service that allows you to read a number of different comics on &#8230; <a href="https://codethink.no-ip.org/archives/511">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I wanted to take a brief moment to invite anyone who stumbles across this post to beta-test my latest personal project; <a href="http://webcomix.no-ip.org" target="_blank">Webcomix</a>.  Webcomix is a simple web-comic aggregation service that allows you to read a number of different comics on a single page.  Here is a screenshot of it in action:</p>
<p><a href="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/03/webcomix.png" rel="lightbox[511]"><img src="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/03/webcomix-1200x681.png" alt="Webcomix screenshot" title="Webcomix screenshot" width="640" height="363" class="aligncenter size-large wp-image-512" /></a></p>
<p>Each comic in Webcomix is periodically checked for updates, so if like me you keep tabs on several different web-comics that all update at different intervals then Webcomix will save you from having to remember to refresh half a dozen different websites at various times just to keep up to date.  Simply visit your Webcomix dashboard and you&#8217;re set!</p>
<p>Underneath the covers there&#8217;s a fair bit that I&#8217;m proud of with this app.  First off the entire system is designed to be as lightweight and efficient (in terms of server compute-time and bandwidth) as reasonably possible.  Virtually all of the actual work is handled by the client-side JavaScript.  The handful of tasks that must be performed server-side are optimized with the help of a custom caching layer which ensures that any given computation (or fetch of an external resource) only needs to be performed once.  There is also an additional caching layer in the client used to prevent it from making any given request to the server more than once per session.  </p>
<p>The server itself is client-agnostic and provides a simple JSON-based API, meaning that while the initial incarnation of Webcomix is in the form of a web-app it should be just as easy to package the same functionality in a mobile, desktop, or other flavor of application.  But that&#8217;s a project for another day.</p>
<p>Anyhow, please note that Webcomix should be considered to be beta software at the moment.  So if you find any bugs or have any suggestions for new features or improved functionality then please don&#8217;t hesitate to say so in the comments section.  </p>
<p>Also, the list of comics currently available in Webcomix is not set in stone and is only based upon my personal preferences at the moment.  Webcomix is designed in a way that makes adding additional comics a trivial task, so if your favorite comic is currently not in the list then I encourage you to post a request in the comments section so that I can add it.  </p>
<p>Lastly, if anyone has any good ideas for how to extend the comic selection UI to handle a large number of comics that they&#8217;d like to share, then please do.  The current interface with its basic rows of checkboxes is obviously not sufficient for handling hundreds (or even dozens) of comics.  It needs to be replaced with something better (or at least, collapsible) soon.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/511/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code Formatting Plugin Updated</title>
		<link>https://codethink.no-ip.org/archives/144</link>
		<comments>https://codethink.no-ip.org/archives/144#comments</comments>
		<pubDate>Sat, 29 Jan 2011 05:32:46 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[banter]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=144</guid>
		<description><![CDATA[I&#8217;ve just updated the code formatting/syntax highlighting plugin used by this site to the very cool Syntax Highlighter Evolved. This plugin is a marked improvement over the previous plugin, providing such niceties as automatic non-copyable line numbers, horizontal scrolling, built-in &#8230; <a href="https://codethink.no-ip.org/archives/144">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve just updated the code formatting/syntax highlighting plugin used by this site to the very cool <a href="http://www.viper007bond.com/wordpress-plugins/syntaxhighlighter/" target="_blank">Syntax Highlighter Evolved</a>.  This plugin is a marked improvement over the previous plugin, providing such niceties as automatic non-copyable line numbers, horizontal scrolling, built-in highlighting rules for just about any common language, and so on.   </p>
<p>No other news to report at the moment, I just wanted to publicly show my support for this excellent WordPress plugin.</p>
<p>Update:  Much as I still love this plugin, it did introduce a pretty severe layout bug in Internet Explorer (any post with a code block in it would be stretched beyond the width specified in the theme layout, causing the posts to overlap with the right-nav section).  I fixed this by adding the following to my IE stylesheet:</p>
<pre class="brush: css; title: ; notranslate">.entry-content {
	width: 100%;
}</pre>
<p>And while we&#8217;re on the subject, the <a href="http://wordpress.org/extend/plugins/lightbox-2/" target="_blank">image lightbox plugin</a> also did not work correctly in Internet Explorer by default (the background overlay was solid black instead of translucent).  I had to add the following CSS to get it working (again in the IE-only stylesheet):</p>
<pre class="brush: css; title: ; notranslate">#stimuli_overlay {
    display: none;
}</pre>
<p>Note that this completely removes the background overlay.  I could probably get the alpha set correctly without too much more fuss, but I think this works well enough for now.</p>
<p>To my fellow web-developers, I can only say the following:  I know it&#8217;s fun to dump on IE for its lack of standards compliance, poor performance, and other failings, but at the end of the day IE is still the most used browser in the world, so it behooves us to always test our work in Internet Explorer when authoring online content or when authoring any code that will be used to generate online content.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/144/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working FLAC and Vorbis Support in Windows Media Player</title>
		<link>https://codethink.no-ip.org/archives/94</link>
		<comments>https://codethink.no-ip.org/archives/94#comments</comments>
		<pubDate>Fri, 28 Jan 2011 13:28:15 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[configuration]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[media]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=94</guid>
		<description><![CDATA[Hot off the heels of the &#8220;SMOOTH Processor&#8221; debacle, I&#8217;m faced with the task of reapplying one of my favorite Windows 7 configuration tweaks. Namely, the addition of FLAC (and also Vorbis, Speex, and so on) support to Windows Media &#8230; <a href="https://codethink.no-ip.org/archives/94">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Hot off the heels of the &#8220;SMOOTH Processor&#8221; debacle, I&#8217;m faced with the task of reapplying one of my favorite Windows 7 configuration tweaks.  Namely, the addition of FLAC (and also Vorbis, Speex, and so on) support to Windows Media Player.  Now I know there are a variety of free media players that have this built-in, and for the longest time I would actually use Winamp3 (along with the quite awesome queue-sidecar plugin) to handle all of my media playback needs.  But as time wore on and operating-systems evolved I didn&#8217;t have the patience to continue coaxing my Winamp3 install into working with the next latest and greatest OS version, nor the tolerance for its sporadic but annoying random crashes, and when Windows 7 rolled out I was presented with a compelling reason to ditch Winamp3 (and every other alternative) in favor of Windows Media Player:  Homegroups.  </p>
<p>Homegroups allow for much simplified sharing of multimedia and other content between computers on a network.  There is very little explicit configuration needed, and when an application integrates with the Homegroup properly there is really no noticeable difference between a local resource and one that&#8217;s being streamed from some other computer on the Homegroup.  This makes for a very cool experience when it all works, and in Windows Media Player it works seemlessly.  My media library can be distributed across several systems, and yet from each one I can access the entire volume as if it is all local to that particular machine.  And it just works, flawlessly, with no onerous setup or manual cajoling needed on my part.  This is what good software is supposed to do; merge invisibly into the background so that the user can accomplish a complex task as if by magic, and currently only Windows Media Player does it.  </p>
<p>I&#8217;m sure that situation will change in the near future, but at the moment its seamless Homegroup integration makes Windows Media Player the only media player that I am interested in using.  And that means that some of its other shortcomings, such as a complete lack of support for a variety of free and open codecs and file formats, need to be dealt with.  Now there are a number of tutorials on this subject already, but many of them give inaccurate or incomplete information.  In the interest of having a complete set of instructions that actually work, if you want to enable FLAC/Vorbis/etc. support in Windows Media Player, do the following:</p>
<ol>
<li>Install the <a href="http://www.xiph.org/dshow/" target="_blank">DirectShow filters/codecs</a>.</li>
<li>Install the <a href="http://bmproductions.fixnum.org/wmptagplus/" target="_blank">Tag Support</a> plugin.</li>
<li>OPTIONAL:  If, like me, you included your FLAC folders/files in your library <em>before</em> installing the above packages, then you also need to <a href="http://www.dalepreston.com/Blog/2007/03/windows-media-player-metadata-backup.html#rebuilding" target="_blank">rebuild your Windows Media Player library</a>.  Make sure you close Windows Media Player and shut down its network sharing service either by stopping it under &#8216;<em>Control Panel -> Administrative Tools -> Services</em>&#8216; or by killing the &#8216;<em>wmpnetwk.exe</em>&#8216; process in the Task Manager before attempting to delete or rename its configuration folder.</li>
</ol>
<p>And that&#8217;s really all there is to it.  You may or may not end up with the ability to seek within and/or see the duration of FLAC files.  I&#8217;ve seen it happen both ways on occasion, it seems like it either works or not depending upon the mood that Windows Media Player happens to be in when these plugins are installed.  But the important bit is that all the previously unsupported files will now show up correctly in your library, and also (of course) that they are now playable.</p>
<p>And in other news, the rebuilding continues, slowly.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/94/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache + PHP = Headache</title>
		<link>https://codethink.no-ip.org/archives/13</link>
		<comments>https://codethink.no-ip.org/archives/13#comments</comments>
		<pubDate>Mon, 24 Jan 2011 12:36:56 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[configure]]></category>
		<category><![CDATA[install]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://localhost/wordpress/?p=13</guid>
		<description><![CDATA[Fresh out of installing and configuring Apache and PHP so that I could get this WordPress blog up and running, I feel there&#8217;s a topic worthy of some brief mention here.  Namely, the proper (which I mean not in the &#8230; <a href="https://codethink.no-ip.org/archives/13">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Fresh out of installing and configuring Apache and PHP so that I could get this WordPress blog up and running, I feel there&#8217;s a topic worthy of some brief mention here.  Namely, the proper (which I mean not in the &#8220;pedantically correct&#8221; sense but more in the &#8220;do this and it will actually work&#8221; sense) way to get Apache and PHP talking to each other after installing them both for the first time.  And to be as clear as possible here, this information pertains specifically to Apache version 2.2.17 and PHP version 5.3.5 (thread-safe).  Mileage may vary with different software versions.</p>
<p>Now back in the day, I would use a nifty little SourceForge project called <a title="phptriad" href="http://sourceforge.net/projects/phptriad/" target="_blank">phptriad</a> to handle all of the little installation and configuration nonsensicalities for me.  Phptriad was quick, easy, and generally worked straight away.  There&#8217;s just one major problem with it; the project hasn&#8217;t seen any updates since September 9th of the year 2000.  Using it nowadays consigns one to hopelessly outdated versions of Apache and PHP (and also MySQL).  Versions that are so hopelessly outdated that they do not meet the minimum requirements for running WordPress.</p>
<p>So I decided that this time around I would do things the correct way, and install the latest version of Apache, the latest version of PHP, and then configure them to talk with each other.  &#8220;How hard can it be&#8221;, I recall myself saying.  The PHP installer even had an Apache configuration step that seemed like it would handle the entire process automatically.  But sadly that was not the case; the automatic configurator did nothing useful, and while the configuration process was not hard it was exceedingly poorly documented and circuitous, turning what should have been a 2-minute task into a nearly 2-hour endeavor.</p>
<p>Now, do a quick Google search for Apache and PHP configuration issues and you will find countless posts suggesting adding minor variations of the following directives to Apache&#8217;s <em>httpd.conf</em> file:</p>
<pre class="brush: plain; title: ; notranslate">AddHandler application/x-httpd-php .php .phtml
AddType application/x-httpd-php .php</pre>
<p>Seems like a simple enough fix, but none of the myriad variations of these two directives did the trick.  It makes sense when you think about it, considering that all these directives do is associate <em>.php</em> files with a MIME type.  Left wide open is the question of how Apache is supposed to know what that MIME type actually means, how it should be handled, and where to find the handler.  Yes, the <em>php5_apache22</em> module is being loaded as well, but the module isn&#8217;t magic; Apache still needs to know when and how it should use it.  So essentially what&#8217;s missing is a mapping to tell Apache &#8220;for MIME type &#8216;x&#8217;, use program &#8216;y'&#8221;.  After far too much searching, I found a page that also mentioned adding the following directive:</p>
<pre class="brush: plain; title: ; notranslate">Action application/x-httpd-php &quot;/path/to/your/php.exe&quot;</pre>
<p>And finally there was the missing piece.  The AddType (or if you prefer, AddHandler) directive associates <em>.php</em> files with a particular MIME type, and the Action directive maps that MIME type to a concrete resource that Apache can use to process items of that type.  Apache now knows both what a <em>.php</em> file is, and how to process it, and like magic the server behaves as it should.  All told far too much digging was needed to uncover that one critical line.  </p>
<p>For reference, the complete PHP configuration section in my <em>httpd.conf</em> file looks like so:</p>
<pre class="brush: plain; title: ; notranslate">PHPIniDir &quot;~/apache/php&quot;
LoadModule php5_module &quot;~/apache/php/php5apache2_2.dll&quot;
AddType application/x-httpd-php .php
Action application/x-httpd-php &quot;~/apache/php/php.exe&quot;</pre>
<p>I suspect that the actual MIME type assigned to <em>.php</em> files matters very little here, so long as the type is consistent between the &#8216;AddType&#8217; directive and the &#8216;Action&#8217; directive.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/13/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
