<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Donat Studios</title>
    <link>http://donatstudios.com/</link>
    <description></description>
    <atom:link rel="self" type="application/rss+xml" href="http://donatstudios.com/feed.rss"/>
    <image>
      <url>http://donatstudios.com/images/site/moustache.png</url>
      <link>http://donatstudios.com/</link>
      <title>Donat Studios</title>
    </image>
    <item>
      <guid>http://donatstudios.com/Simple-Single-Pass-Doubly-Linked-Flat-Tree-Building-Algorithm</guid>
      <title>Simple Single Pass Doubly Linked Flat Tree Building Algorithm</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Fri, 06 Jan 2012 15:55:47 CST</pubDate>
      <link>http://donatstudios.com/Simple-Single-Pass-Doubly-Linked-Flat-Tree-Building-Algorithm</link>
      <description><![CDATA[<p>A hierarchy is a common structure, especially in web development.&nbsp; The problem with hierarchies is they need to be flattened to be stored in a relational database, and then expanded again after being pulled out.&nbsp; </p>
<fieldset><legend>An Example Hierarchy</legend>
<ul>
  <li>Top level item</li>
  <ul>
    <li>Sub Item</li>
    <ul>
      <li>Sub Sub Item</li>
      <ul>
        <li>Sub Sub Sub Item</li>
      </ul>
    </ul>
    <li>Sibling of Sub Item</li>
  </ul>
  <li>Top level as well</li>
</ul>
</fieldset>
<p>&nbsp;</p>
<p>A common and simple way to store them is with a table structure similar to the following.</p>
<table border="0" cellspacing="0" cellpadding="0">
  <tr>
    <td width="77" valign="top"><p>id</p></td>
    <td width="63" valign="top"><p>parent_id</p></td>
    <td width="161" valign="top"><p>title</p></td>
  </tr>
  <tr>
    <td width="77" valign="top"><p>1</p></td>
    <td width="63" valign="top"><p>0</p></td>
    <td width="161" valign="top"><p>Top level item</p></td>
  </tr>
  <tr>
    <td width="77" valign="top"><p>2</p></td>
    <td width="63" valign="top"><p>0</p></td>
    <td width="161" valign="top"><p>Top level as well</p></td>
  </tr>
  <tr>
    <td width="77" valign="top"><p>3</p></td>
    <td width="63" valign="top"><p>1</p></td>
    <td width="161" valign="top"><p>Sub Item</p></td>
  </tr>
  <tr>
    <td width="77" valign="top"><p>4</p></td>
    <td width="63" valign="top"><p>1</p></td>
    <td width="161" valign="top"><p>Sibling of Sub Item</p></td>
  </tr>
  <tr>
    <td width="77" valign="top"><p>5</p></td>
    <td width="63" valign="top"><p>3</p></td>
    <td width="161" valign="top"><p>Sub Sub Item</p></td>
  </tr>
  <tr>
    <td width="77" valign="top"><p>6</p></td>
    <td width="63" valign="top"><p>6</p></td>
    <td width="161" valign="top"><p>Sub Sub Sub Item</p></td>
  </tr>
</table>
<p>Now there are several ways to return this to a multidimensional array or other navigable structure. A painfully common and naïve way would be recursive queries ala:</p>
<pre>
function fetch_items($parent = 0) {
	$data = array();
	$qry = mysql_query(&quot;select * from `tablename`&nbsp; where parent_id = &quot; . (int)$parent );
	while( $row = mysql_fetch_array($qry) ) {
		$data = array('data' =&gt; $row, 'children' =&gt; fetch_items($row['id']));
	}
	return $data;
}
  </pre>
<p>The problem with this approach is the sheer number of queries this approach uses. Our simple example hierarchy would execute 6 queries, whereas more complicated hierarchies would execute many more.</p>
<p>A better approach is to pull all the data out with a single query, and then process it into the structure we need.&nbsp; There are several ways to do this, but I find the following DOM like structure this generates incredibly useful.</p>
<pre>
function fetch_tree() {
	$data = array();
	$qrt&nbsp; = mysql_query(&quot;select * from `tablename` order by parent_id asc&quot;);
	while( $row = mysql_fetch_array($qry) ) {
		$data[ $row['id'] ]['data'] = $row;
		$data[ $row['parent_id'] ]['children'][ $row['id'] ] =&amp; $data[ $row['id'] ];
  		$data[ $row['id'] ]['parent'] =&amp; $data[ $row['parent_id'] ];
 	}
	return $data;
}
  </pre>
<p>Essentially, in a <strong>single pass</strong> through the data, this gets us an array of hierarchy elements, where rather than an element directly having its children, every entry has a pointer to its parent element as well as an array of pointers to its children. This is incredibly flexible, and as the tree is flattened it allows you to start at any point in the hierarchy by ID ala $data[<em>id</em>], and navigate your way up or down. Viewing any elements children is as simple as $data[<em>id</em>][ 'children'], and its parent as simple as $data[<em>id</em>]['parent'].</p>
<p>I use this basic methodology a ton in my work, personal and professional (the comments and sitemap of this site are powered by it!) but the concept seems foreign when I try to explain it to people. &nbsp;I hope this explanation sparks some ideas for people.</p>
]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/Damn-Simple-PHP-ASCII-Art-Generator</guid>
      <title>Damn Simple PHP ASCII Art Generator</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Thu, 10 Nov 2011 07:18:43 CST</pubDate>
      <link>http://donatstudios.com/Damn-Simple-PHP-ASCII-Art-Generator</link>
      <description><![CDATA[<p>So yesterday I was bored and asked my friend what I should do.  She replied "I don't know, draw ASCII art or something!" and sitting there with the terminal open I kind of wondered what it would take to write one of those image to ASCII scripts.</p>
<p>20 minutes later I had the following PHP Shell Script! It works by simply sampling the saturation of every X<i>th</i> pixel and mapping that saturation to a character from an array. There is no nearest-neighboring or anything like that, just straight up sampling.</p>
 
<h2>Huzzah!</h2>
<a http://donatstudios.com/Array rel="lightbox"><img http://donatstudios.com/Array alt="ASCII JORIE is made of ASCII" style="margin: auto; display: block; width: 44%; float: right;" /></a>
<p>And there you have it! A whopping 35 lines of code. There is a ton of tweaking you can do like changing the array of characters, or adjusting the $scale variable which is simply how wide of a sample it makes.  Setting it to 1 for instance should sample every pixel on the Y and every other pixel on the X (so it scales propperly). To the right is a sample output of the script.</p>
<h2>Do You Trust Me?</h2>
<p>The script accepts local or remote image paths as the first argument.  The following is a simple usage example you can use to get you started.</p>
<pre class="terminal">./ascii.php "http://donatstudios.com/images/site/JesseDonat.jpg"</pre>
<p>It was a fun little project and I look forward to seeing if/what the internet comes up with for it. <a http://donatstudios.com/Array>Fork me on Github</a>, or post links in the comments!  Happy hacking!</p>
<br clear="all" />]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/Lion-Photobooth-Repair</guid>
      <title>Mac OSX Lion Photo Booth Plist Rebuild/Repair Script</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Tue, 26 Jul 2011 23:13:23 CST</pubDate>
      <link>http://donatstudios.com/Lion-Photobooth-Repair</link>
      <description><![CDATA[<p>I recently upgraded from an aging MacBook Pro to a much more nubile MacBook Air. I am frankly delighted with the Air in every way. The problem I encountered though is the sparse image backup of the MacBook Pro I made with Carbon Copy Cloner before I wiped the drive and sold it is seemingly corrupted and will not mount.</p>
<p>I did though have a backup of my Photo Booth Photos and wanted to get them to be recognized by the application. It is admittedly simply a matter of entering them into the Recents.plist file, but having several hundred photos across three operating systems and three naming schemes (was that *really* necessary, Apple?) getting these into the proper order by hand would have been a nuisance to say the least.</p>
<p>Alas! A use for my PHP skills! I went ahead and wrote a simple PHP based shell script you can use to create a new .plist file with your images properly ordered.</p>
<p>This will back up your current Recents.plist as Recents.plist.bk.[time] so if you decide to roll it back, it will be there for you</p>
<h2>Basic Operation</h2>
<h3>Familiar with Git?</h3>
<p>Simply executing <pre class="terminal">git clone git://gist.github.com/1108691.git PhotoBoothRepair</pre> should both download it and set it executable.</p>
<h3>Not Familiar with Git?</h3>
<ul>
	<li>Ensure that all the Photos / Movies you want loaded into Photo Booth are located in <pre>~/Pictures/Photo Booth Library/Pictures/</pre></li>
	<li><strong>Ensure Photo Booth is closed</strong> to avoid overwriting our changes</li>
	<li>Save the file below somewhere accessible to you via Terminal.</li>
	<li>Correct the noted path at the top of the file to reflect your home folder</li>
	<li>Navigate in Terminal to the directory where you saved the shell script</li>
	<li>Set the file executable by running <pre class="terminal">chmod +x Photobooth_rebuild.sh.php</pre></li>
	<li>Execute the shell script <pre class="terminal">./Photobooth_rebuild.sh.php</pre></li>
	<li>All Done - Fire up Photo Booth to see our results!</li>
</ul>
<p>I welcome any and all feedback.  Feel free to fork this code on Github - I'm open to any updates.</p>
<h2>Limitations</h2>
<ul>
	<li>It presumes all Leopard format names are pre Snow Leopard and Lion simply for lack of anything to go on (They're just numbered)</li>
</ul>
 
<p>Well let me know in the comments if you find this useful.  I wrote it for my personal use and it saved me a ton of time.</p>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/PhpED-Dark-Theme</guid>
      <title>Nusphere PhpED Dark Theme</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Thu, 07 Jul 2011 16:34:57 CST</pubDate>
      <link>http://donatstudios.com/PhpED-Dark-Theme</link>
      <description><![CDATA[<p>It would seem there is a fair deal of call for an updated version of my PhpED dark theme from colleagues as well as random folks on the internet who’ve seen screenshots of my PhpED installation.  I previously had my Dark Theme for 5 linked on my Review of PhpED, but I figured I could have a page dedicated to it.</p>

<fieldset><legend>Screenshots</legend>
<a http://donatstudios.com/Array rel="lightbox"><img http://donatstudios.com/Array alt="PhpED Dark Theme PHP" style="margin: auto; display: block; width: 30%; float: left;" /></a>
<a http://donatstudios.com/Array rel="lightbox"><img http://donatstudios.com/Array alt="PhpED Dark Theme CSS"  style="margin: auto; display: block; width: 30%; float: right;" /></a>
<a http://donatstudios.com/Array rel="lightbox"><img http://donatstudios.com/Array alt="PhpED Dark Theme HTML" style="margin: auto; display: block; width: 30%; margin: 0 auto;" /></a>
</fieldset>
<h2>Download and Installation</h2>
<p>The first step is to download the proper version.  <br />Click here to download the <a http://donatstudios.com/Array target="_blank">PhpED 6 Version</a> or here to download the <a http://donatstudios.com/Array  target="_blank">PhpED 5 Version</a>.</p>
<p>After you have downloaded the file you will need to replace your hl.cfg. </p><p>In Windows 7 or Vista this should be located in or around: <pre>C:\Users\<strong>YOUR_USER_NAME</strong>\AppData\[<em>Roaming</em> / <em>Local</em>]\NuSphere\PhpED\config</pre>
<br />Likewise in XP it should be located in something like: <pre>C:\Documents and Settings\<strong>YOUR_USER_NAME</strong>\Application Data\NuSphere\PhpED\config</pre>
</p><p>The final step is to simply change your background color to a dark color.  The background color is oddly saved in a different configuration file than the highlighting. This can be found in <strong>Tools</strong> &rArr; <strong>Settings</strong> &rArr; <strong>Editor</strong> &rArr; <strong>Appearance</strong></p>
<p>While you're in there you may want to tweak the settings some to your taste, but that is all there is to it.</p>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/MPO-to-JPEG-Stereo</guid>
      <title>MPO to Anaglyph/Stereo-JPEG</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Thu, 12 May 2011 23:44:27 CST</pubDate>
      <link>http://donatstudios.com/MPO-to-JPEG-Stereo</link>
      <description><![CDATA[<fieldset style="float: left; width: 52%; margin-bottom: 22px; margin-right: 22px;"><legend>Try it out!</legend>
	 
</fieldset>

<p style="clear:right;"><strong>Update May 12th, 2011</strong> Anaglyph ability added! I don't believe Red/Green is correct but I have a pair of glasses on the way to test it out.</p>
<p>Convert MPO files like those generated by the Nintendo 3DS into Stereoscopic JPEG Images or Anaglyph like you would use 3D glasses for.</p>
<p>Examples and more info to come!</p>
<p>While you're here, feel free to download the source below.   Source to anaglyph will be available soon after some slight refactoring.</p>

<fieldset style="margin-bottom: 22px; clear: both;"><legend>Gallery</legend>

</fieldset>

<table class="datatable" style="width: 100%" cellpadding="0" cellspacing="0">
<tr><th align="left">Build</th><th align="left">Date</th><th align="left">Message</th></tr><tr class="odd"><td align="left">0.1<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2011-04-13T09:01:51-05:00" datetime="2011-04-13T09:01:51-05:00">Apr. 13, 2011</time></td><td align="left"><small>2 bytes skipped on beginning of second+ image breaking on PHP 5.2.x - corrected</small></td></tr></table>
]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/WPF-VBNet-JumpList-Example</guid>
      <title>Simple WPF VB.Net JumpList Example</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Wed, 06 Apr 2011 23:00:31 CST</pubDate>
      <link>http://donatstudios.com/WPF-VBNet-JumpList-Example</link>
      <description><![CDATA[<p>Today I decided to spruce up a VB.Net application I wrote in
	college and still use almost daily. In the process of converting it
	from .Net 2 to .Net 4 I wanted to add a splash of Windows 7 goodness; there were some
	very simple operations I wanted to add to JumpLists.  The problem I ran into with all the examples I
	could find is that they either called entirely different applications (the Microsoft
	examples all called <i>Notepad</i>) or
	the example was in C#.  The
	application is in VB.Net and I intend to keep it that way, as it is my .Net
	language of choice.</p>
<p>The interesting problem with JumpLists is they are just
	shortcuts.  They call an executable with
	the specified arguments. Microsoft’s reasoning for this is that they are still
	available while the program is no longer running. The initial <i>execution</i> of an application placed in
	the taskbar registers the JumpLists, after which point they are cached by the
	system and continue to be available even when the application is no longer
	running. This potentially limits the usefulness of JumpLists as they do start a
	new instance of your application.  If
	anyone knows how to catch the arguments on a single instance application, I
	would be <i>very</i> interested to hear
	it.  The best I’ve come up with is simply
	passing messages to my current instance from a new instance and then
	terminating the second instance, but this is awkward to my eye.</p>
<p>XAML can be used to create JumpLists in the Application.xaml
	file, which many other examples will demonstrate – but the issue here is there
	is no way to get the path to the current executable via XAML, so you can only
	call <i>other</i> executables whom you know
	the full path to.</p>
<p>The answer then is to create our JumpLists dynamically.  The best place to do this is in your
	Application.xaml.vb file.  The New method
	will be used to instantiate and register the JumpLists, whereas the Startup
	event will be used to handle arguments passed to the new instance of our
	application.</p>
<p>Below is a very simple example of JumpLists not too far off from what I ended up going with in my own application.  Feel free to leave me comments as to any improvements or changes you would make, or go ahead and fork the gist.</p>

 ]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/PHP-Parser-HTTP_USER_AGENT</guid>
      <title>PHP User Agent Parser</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Tue, 29 Mar 2011 16:51:09 CST</pubDate>
      <link>http://donatstudios.com/PHP-Parser-HTTP_USER_AGENT</link>
      <description><![CDATA[<fieldset><legend>Demo</legend>

</fieldset>

<br clear="all"/>
<div class="GithubFeed"><h2>Recent Activity</h2><h3><time class="entryDate" title="2011-03-30T00:58:34-05:00" datetime="2011-03-30T00:58:34-05:00">Mar. 30, 2011</time></h3>Basic Camino support and tests added<hr />Kindle Support Roughed In<hr /><h3><time class="entryDate" title="2011-03-28T18:26:29-05:00" datetime="2011-03-28T18:26:29-05:00">Mar. 28, 2011</time></h3>Init commit<hr /></div>

<p>There are many User Agent string parsers out there, many PHP
	ones infact, but none of what I tested were able to do <i>all</i> of the following.</p>
<ol>
	<li>Correctly identify certain versions of IE7 and
	above that included a user string mentioning IE6 as follows
		<ol>
			<li><pre style="width: 389px">Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1))</li>
		</ol>
	</li>
	<li>Correctly identify various mobile platforms,
				Android and Windows Phone 7 in particular.</li>
	<li>Operates simply without large class structures.</li>
</ol>
<p>This is why I set about building my own.  I don’t guarantee it to be perfect, but it
	works for my needs. I <b>strongly</b> welcome <a http://donatstudios.com/Array target="_blank">forking</a> and pull requests through <a http://donatstudios.com/Array target="_blank">Github</a> for
	any changes.  </p>
<p> Comments are more than welcome below.</p>
<p>Known Limitations</p>
<ul>
	<li>Does not detect Linux platform other than
		Android</li>
	<li>Does not detect Ice Weasel as Firefox</li>
	<li>Probably many others not coming to mind right now.</li>
</ul>
<p>View the test suite of User Agents I'm currently running it against <a http://donatstudios.com/Array target="_blank">here</a>.</p>

<div class="GithubFile"><pre><code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #FF8000">/**<br />*&nbsp;Parses&nbsp;a&nbsp;user&nbsp;agent&nbsp;string&nbsp;into&nbsp;its&nbsp;important&nbsp;parts<br />*&nbsp;<br />*&nbsp;@param&nbsp;string&nbsp;$u_agent<br />*&nbsp;@return&nbsp;array&nbsp;an&nbsp;array&nbsp;with&nbsp;browser,&nbsp;version&nbsp;and&nbsp;platform&nbsp;keys<br />*/<br /></span><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">UserAgentParser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$u_agent&nbsp;</span><span style="color: #007700">)&nbsp;{&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">=&nbsp;array();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">#&nbsp;^.+?(?&lt;platform&gt;Android|iPhone|iPad|Windows|Macintosh|Windows&nbsp;Phone&nbsp;OS)(?:&nbsp;NT)*(?:&nbsp;[0-9.]+)*(;|\))<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">if&nbsp;(</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(</span><span style="color: #DD0000">'/^.+?(?P&lt;platform&gt;Android|iPhone|iPad|Windows|Macintosh|Windows&nbsp;Phone&nbsp;OS)(?:&nbsp;NT)*(?:&nbsp;[0-9.]+)*(;|\))/im'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$u_agent</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$regs</span><span style="color: #007700">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'platform'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">$regs</span><span style="color: #007700">[</span><span style="color: #DD0000">'platform'</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">""</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">#&nbsp;(?&lt;browser&gt;Camino|Kindle|Firefox|Safari|MSIE|AppleWebKit|Chrome|IEMobile|Opera)(?:[/&nbsp;])(?&lt;version&gt;[0-9.]+)<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">preg_match_all</span><span style="color: #007700">(</span><span style="color: #DD0000">'%(?P&lt;browser&gt;Camino|Kindle|Firefox|Safari|MSIE|AppleWebKit|Chrome|IEMobile|Opera)(?:[/&nbsp;])(?P&lt;version&gt;[0-9.]+)%im'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$u_agent</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">PREG_PATTERN_ORDER</span><span style="color: #007700">);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">]&nbsp;==&nbsp;</span><span style="color: #DD0000">'AppleWebKit'&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;(&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'platform'</span><span style="color: #007700">]&nbsp;==&nbsp;</span><span style="color: #DD0000">'Android'&nbsp;</span><span style="color: #007700">&amp;&amp;&nbsp;!(</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">)&nbsp;)&nbsp;||&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">array_search</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Chrome'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;)&nbsp;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'Chrome'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}elseif(&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">array_search</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Kindle'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;)&nbsp;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'Kindle'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}elseif(&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">array_search</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Safari'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;)&nbsp;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'Safari'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'webkit'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">][</span><span style="color: #0000BB">$key</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;}elseif(&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">array_search</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Opera'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;)&nbsp;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">][</span><span style="color: #0000BB">$key</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">][</span><span style="color: #0000BB">$key</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;}elseif(&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">]&nbsp;==&nbsp;</span><span style="color: #DD0000">'MSIE'&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">array_search</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'IEMobile'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;)&nbsp;)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'IEMobile'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'MSIE'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$key&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">][</span><span style="color: #0000BB">$key</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;}else{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">$result</span><span style="color: #007700">[</span><span style="color: #DD0000">'version'</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'browser'</span><span style="color: #007700">]&nbsp;==&nbsp;</span><span style="color: #DD0000">'Kindle'&nbsp;</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'platform'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'Kindle'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">;<br /><br />}</span>
</span>
</code></pre></div>

<div style="text-align: center"><a http://donatstudios.com/Array target="_blank">Source Availbile at Github as Well</a></div>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/RewriteRule_Generator</guid>
      <title>301 RewriteRule Generator</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Mon, 28 Feb 2011 19:58:49 CST</pubDate>
      <link>http://donatstudios.com/RewriteRule_Generator</link>
      <description><![CDATA[<p>I find myself often needing to set up a large number of 301 redirects from an excel file of old to new url’s. Until this point, writing these had been a fairly exhausting process as you need to be certain to escape every character that could be picked up by the regular expression engine, or risk unintended consequences. On top of that, writing these rewrites to catch GET parameters in any order is complex to say the least.  While working through a large list of 301s for a very picky server where <em>Redirect 301</em> style redirects were not an option, I began setting up RewriteRule's by hand and decided there had to be a better way. Voila! My 301 RewritRule Builder was born.
	</p><img http://donatstudios.com/Array alt="Excel Usage Example" style="float: right; padding-left: 11px;" />
<p>You can simply enter a list of tab or space delimited urls (copied from Excel works great) and it will spit out the generated RewriteRule’s for you. GET parameters on the old urls are broken up and built into multiple RewriteCond’s set up to work in any passed order. 	</p>
<p>I hope someone finds this useful.  Any comments are welcome below, of feel free to <a http://donatstudios.com/Array target="_blank">fork me on github</a>! </p>


<fieldset> <center><small><a http://donatstudios.com/Array target="_blank">Fork my source on Github!</a></small></center></fieldset>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/Google_Killed_The_Internet</guid>
      <title>Opinion: Google Killed the Internet</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Sun, 19 Dec 2010 22:35:10 CST</pubDate>
      <link>http://donatstudios.com/Google_Killed_The_Internet</link>
      <description><![CDATA[<h2>Googles Page Speed &ldquo;Optimizations&rdquo; Make Learning Difficult</h2>
<p>If you, as I, grew up during the web bubble we call the 90&rsquo;s and were interested at all in web development my guess is that you probably didn&rsquo;t learn most of your skills from a book or a class.  You probably would run across a site that had something cool on it and ponder  &ldquo;Oh my, how does that work?&rdquo; right click, view source, and after some digging were enlightened.  I&rsquo;m certain this is how most of my generation learned their HTML/CSS/JavaScript skills, it is certainly how I did, and often how I continue though now I have tools to help me even further pick apart a page such as Firebug.</p>
<p>Where I take issue is CSS and more so JavaScript minifying. Google wants essentially all your CSS and JavaScript minified. This lessens the bandwidth <em>Google</em> has to use, but in the process makes the source complete illegible to a human being.</p>
<p>I personally, on <em>this site</em>, lose a fair deal of my Page Speed Score because &ldquo;Minifying <a http://donatstudios.com/Array target="_blank">http://donatstudios.com/js/general.js</a> could save 311B (23% reduction)&rdquo;.   My general.js file is at the moment 1.3 kilobytes; I am losing points off my Page Speed score over 311 bytes simply because I want my source code to remain legible.  Can we please get a sanity check on this, Google.  311 bytes is not going to kill you.</p>
<h2>SEO is Destroying the Spirit of the Internet</h2>
<p>Back in the hay day of Geocities if you did a search you were likely to get a few if not mostly amateur pages in your results.  They weren&rsquo;t usually <em>well designed</em> perse, but they were often <em>very</em> useful. I can recall of the top of my head a few instances where they saved the day.</p>
<p>In steps &ldquo;Search Engine Optimization&rdquo;. Corporations are gaga over paying people to dig through content, study their keywords, rewording things and saturating content with keywords (often at the cost of readability I might add).</p>
<p>Now let&rsquo;s compare that to an amateur, who&rsquo;s content is designed for <em>human consumption</em> rather than <em>googles</em> and now has no way to keep up in this arms race. There usually isn&rsquo;t the money nor the desire to pump into SEO and content development.  They just want to provide some useful information to the public.  These kinds of sites are becoming increasingly hard to find, with corporate sites taking the lion&rsquo;s share of the hits.</p>
<p>Frankly I believe a lot of great content is getting missed thanks to SEO.  The spirit of the internet years ago was driven around the fact that anyone could write something, and have it read by millions of people.  While this is still the case, I find it far less likely now than it has been in previous years.  I don&rsquo;t think there is a solution; I just find the corporatization of the web a little disheartening.</p>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/Grid_CSS_Versus_The_Web</guid>
      <title>Grid Style Sheets vs. The Semantic Web</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Tue, 19 Oct 2010 17:43:21 CST</pubDate>
      <link>http://donatstudios.com/Grid_CSS_Versus_The_Web</link>
      <description><![CDATA[<h2>Grid Style Sheets Must Die</h2>
<p>I have been aware of Grid Style Sheets for quite a while, but I long ago dismissed them as a fad like CSS Resets.  Recently though it came to my attention that OSCommerce 2.3 switched to the <a target="_blank" http://donatstudios.com/Array>960 Grid Style</a> to replace its table based layout system.  I spend most of my development time working with OSCommerce and thought it would be good to understand this change so I could decide whether or not to integrate it into our fork.</p>
<p>My general impression playing with the latest nightly of OSCommerce 2.3 from Github though is that I don&rsquo;t like it – maybe I&rsquo;m old school, but in my view Grid Style Sheets go against what we spent the previous decade fighting for, separation of our concerns&hellip; separating presentation and content.</p>
<h3><em>You&rsquo;re Doing it Wrong</em></h3>
<p>Let&rsquo;s talk about <a target="_blank" http://donatstudios.com/Array>separation of presentation and content</a>.</p>
<p>Ideally, content and layout information should be entirely separate.  Class names should be used to <em>describe</em> the <em>data</em> they contain, and <em>nothing to do with</em> the style the class will contain.  You should be able to completely rearrange / restructure a page simply by switching out a stylesheet.  The HTML should strive to be as purely a data delivery mechanism as possible, similar to that of an XML request, and the CSS is there to make it something a human can digest.</p>
<p>Using a Grid stylesheet – your class names <em>purely</em> apply to your <em>specific</em> layout.  Class names like &ldquo;grid_1&rdquo; or &ldquo;container_12&rdquo; are not indicative of content in the slightest, but rather where they are placed on the grid that is your page. <s>Grid_1 will <em>always</em> be leftmost. Always. Might as well use &lt;left&gt;</s> <strong style="color:red">Correction</strong>: Grid_1 will always be one twelfth of your page wide (on a twelve Column Grid) , Grid_2 two twelfths, et cetera. Nothing to do with describing the content contained.</p>
<h3>Grid Style Sheets are <em>Extremely</em> Limiting</h3>
<p>With a well-structured CSS layout, deciding to move your navigation from the left to the right is as simple as flicking a switch.  Usually after changing one to a few lines of CSS, and its switched. It <em>cascades</em> across your entire site and everything floats and adjusts.  Same goes for altering the width, or even the entire flow of your document. You can quite easily decide your left navigation is now a top navigation with no alteration to the content.</p>
<p>Contrast this with a grid style sheet – to reposition <em>anything</em> you will have to <strong>edit the HTML</strong> – change the class you call.  Restructuring a site is a major task. They are essentially <strong><em>tables</em></strong> done in CSS with <em>all the <strong>drawbacks of tables</strong></em><strong> </strong>with few of the benefits (*cough* valign *cough*).</p>
<h3>Why Does this Matter? </h3>
<p>Flexibility, sustainability, scalability – these are not just buzz words – these are important attributes of a well-developed site – these are things a grid layout does not deliver.</p>
<p>Let&rsquo;s look at this from a prebuilt application perspective. In OSCommerce 2.3 the left navigation is classed grid_4 which places it 4 gridlines out of 16, and the content area is push_4 which aptly pushes it over 4.  That defines not only where my navigation appears, but also its size.  Its inflexible without changing HTML, and quite honestly wouldn&rsquo;t work for the <strong>majority</strong> of carts I develop.</p>
<h3>Final Thoughts</h3>
<p>Grids, from a design perspective are not just<em> useful, </em>they&rsquo;re downright<em> ideal</em>.  Clear alignment of elements creating strong visual lines is something strived for.  <strong>Consistent</strong> padding and margins are all very important – and all of these are honorable virtues of a grid style sheet.</p>
<p>I definitely understand the draw and the time saved in the initial build of a site, but a meticulously well engineered style sheet supporting semantic CSS will in the long run pay back the initial investment many times over.</p>
<h3>Post Script</h3>
<p>While writing this, I&rsquo;ve decided <em>I</em> really like the <em>concept</em> and <em>aim</em> of the grid style sheet – and would <em>love it</em> if it did not interfere with the semantic nature of CSS.  If I could simply do something like the following, I would be using it 10 minutes ago.</p>
<pre>#leftnav {

	imports: .grid2;

}</pre>
<p>W3C – I&rsquo;m looking your direction to see this happen.  Until then, I&rsquo;m sticking with my old fashioned meticulously crafted CSS.</p>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/lorem_ipsum_generator</guid>
      <title>Statistics Based Lorem Ipsum Generator</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Wed, 22 Sep 2010 15:02:25 CST</pubDate>
      <link>http://donatstudios.com/lorem_ipsum_generator</link>
      <description><![CDATA[<p>Several months ago I was wondering to myself if you could detect patterns in a list of words and then use those patterns to generate a new list of fake &ldquo;words&rdquo;. A kind of a <em>flavored</em> Lorem Ipsum generator, where I could change the feel of the sentences by switching out the data set.  I&rsquo;m sure thousands of developers have done this before me – but it was a fun thought experiment.</p>
<p>I threw together a little script in PHP to test the idea, and the results were kind of interesting so I figured I'd throw it on my site - Anyway, here are some examples in action – you can hit reload for a random ipsum!  The code and a sample dataset are below.</p>

<fieldset style="clear:both"><legend>Faux English Demo</legend> </fieldset>
<fieldset><legend>Faux Latin-y English Demo</legend> </fieldset>
<fieldset><legend>Faux Japanese Demo</legend> </fieldset>
<br clear="all" />
<br />
You need to supply a set of words for it to base the pattern off - here is my <strong><a target="_blank" http://donatstudios.com/Array>sample dataset</a></strong>.
<br />
 ]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/FastPatch</guid>
      <title>Fast Patches with Git</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Fri, 27 Aug 2010 15:59:26 CST</pubDate>
      <link>http://donatstudios.com/FastPatch</link>
      <description><![CDATA[<p>In my work, I deal with a lot of very similar codebases - and often if I fix something in one project I'll want to fix it in many others.  For a long time this has meant popping open Beyond Compare, which works, but isn't the simplest solution.</p>
<p>I use git on my projects - but they're not similar enough just to be branches. Recently I came up with a way to patch one or more commits from a project to another easily.  Here is a simple shell script I wrote to handle the task.</p>
<p>Simply put, you can use it either by <pre class="terminal">fast-patch.sh /z/my_project</pre> to patch a project with the latest commit from the project in the working directory or with an optional paramater, specify a number of commits, eg <pre class="terminal">fast-patch.sh /z/my_project 5</pre></p>
<p>Also, it will generate a patch log to ~/fastPatch.log which I generally use directly for my commit message by way of <pre class="terminal">git commit -F ~/fastPatch.log</pre></p>
<p>Any comments on how I could improve it, or questions are quite welcome.</p>
 ]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/Balanced_Take_on_Gzip</guid>
      <title>A Balanced Look at GZIP and the User Experience</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Mon, 16 Aug 2010 18:30:31 CST</pubDate>
      <link>http://donatstudios.com/Balanced_Take_on_Gzip</link>
      <description><![CDATA[<p>With Google recently starting to involve load time in search  rankings, there has been a lot of talk about GZIP.  Google Webmaster Tools exclaims "Compressing  the following resources with gzip could reduce their transfer size by <strong>X</strong>KB:". Many people listen to this, and go out looking for a quick fix without realizing that <strong>poor GZIP implementation has a strongly negative effect on  the overall user experience</strong>.</p>
<p>There are two main ways in PHP to go about implementing  GZIP. The first is <a http://donatstudios.com/Array>ob_gzhandler</a>.   Basically all that is really involved in setting this up is adding <code>ob_start(&quot;ob_gzhandler&quot;);</code> anywhere  before headers are sent, and it will blindly handle this for you. </p>
<p>The second is <a http://donatstudios.com/Array target="_blank">zlib.output_compression</a> which while entirely transparent and Zends states that <q cite="http://www.php.net/manual/en/function.ob-gzhandler.php">using zlib.output_compression is preferred over ob_gzhandler().</q></p>
<p>This method can have a huge downside for users.  It can for instance greatly exacerbate the sluggishness  of an already slow page or even site. Right now your probably saying to yourself "What? I  thought GZIP made everything faster. This guy is crazy.". Allow me to explain. </p>
<p>Let&rsquo;s say that you have a site with no all encompasing output  buffer.  As PHP works its way through  your script it occasionally flushes out its internal buffer to apache, which in turn flushes it out to the browser, allowing the browser to begin rendering the incomplete document. Also, let&rsquo;s say as an example you have a hold up slowing down your page in the footer of your site. The  user would already have the rest of the content and could  begin reading  and enjoying the site.</p>
<p>Now let&rsquo;s compare to a site GZIPed with an output buffer  callback, e.g. ob_gzhandler. After the output buffer is started, your code  begins to execute.  Everything echoed is  held in the buffer until the page is completely done and the output buffer closes, at which point it is  GZIPed and flushed out to the user.   The user recieves less bits, but that hold up in the footer we spoke of before halts up the entire  rendering process, and the user cannot see anything  until the footer completes.</p>
<p>For your viewing pleasure, a demonstration:</p>
<fieldset><legend>Side by Side Comparison</legend>
	<table>
		<tr>
			<th>Non-GZIPed</th>
			<th>GZIPed</th>
		</tr>
		<tr><td>
			 
		</td><td>
			 
		</td></tr>
	</table>
    <small>It has come to my attention that Webkit browsers wait for a full result in an iframe to begin rendering - so this example will not work in Safari/Chrome</small>
</fieldset>
<h2>Take Note</h2>
<p>I am not stating that all GZIP is bad. To the contrary, GZIP can be very beneficial and I absolutely sympathize with google wanting to cut down on their bandwidth. If you have Firebug or something similar you can note that the request for the Non-GZIPed example is a whopping 100 <strong>kilobytes</strong>, whereas the GZIPed examples request is a measily 323 <em><strong>bytes</strong></em>! The reason for this is I did not have enough content to get Apache to flush so to get around this I added the following line.</p>
<pre>echo str_repeat(' ', 100000); <em>//This creates 100kb worth of data, enough to trigger my copy of Apache to flush;</em></pre>
<p>Not only does this trick cause Apache to flush,  but it  exagerates the positive effect of GZIP. Simple patterns, or in this case large amounts of whitespace, will compress quite wondefully.</p>
<p>Uncompressed static files, JavaScript and CSS being two of the best examples compress quite well. The best way to do this is on an Apache server is with </p>
<pre>&lt;IfModule mod_deflate.c&gt;<br />
&lt;FilesMatch &quot;\.(js|css)$&quot;&gt;<br />
SetOutputFilter DEFLATE<br />
&lt;/FilesMatch&gt;<br />
&lt;/IfModule&gt;</pre>
<h2>Looking for a Solution</h2>
<p>I've posted a number of questions to Stack Overflow [<a http://donatstudios.com/Array>1</a>]  [<a http://donatstudios.com/Array>2</a>]  researching this writing and actually found very limited help.</p>
<p>It appears murky whether or not the protocol even supports  the functionality of chunking GZIP results into separately compressed blocks,  as would be required to decompress portions before the page is done – you can  chunk a complete GZIP response, but the advantage of this is limited.</p>
<p> Lastly I have seen &ldquo;promises&rdquo; of ob_gzhandler caching the  results leading to a speed boost on a number of blogs – this is purely fiction and not to be trusted.</p>
<h2>Moral of the Story</h2>
<p>Understand what you&rsquo;re doing before you do it.  <em>Blindly</em> using output buffering for GZIP can have adverse effects on your site.  </p>
]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/SimpleCalendar</guid>
      <title>SimpleCalendar</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Wed, 10 Nov 2010 23:54:03 CST</pubDate>
      <link>http://donatstudios.com/SimpleCalendar</link>
      <description><![CDATA[<div class="GithubFeed"><h2>Recent Activity</h2><h3><time class="entryDate" title="2010-07-12T14:32:34-05:00" datetime="2010-07-12T14:32:34-05:00">Jul. 12, 2010</time></h3>Merge branch 'master' of github.com:donatj/SimpleCalendar<hr />Leftover Debugging Echo Removed<hr /><h3><time class="entryDate" title="2010-07-10T12:39:14-05:00" datetime="2010-07-10T12:39:14-05:00">Jul. 10, 2010</time></h3>Added doc blocks to addDailyHtml and clearDailyHtml<hr /><h3><time class="entryDate" title="2010-07-08T13:43:10-05:00" datetime="2010-07-08T13:43:10-05:00">Jul. 8, 2010</time></h3>- Fix for months that start on sunday<br />
- Fix for months that end on saturday<hr />Formatting changes to the calendars surrounding table.<hr />Removed an accidental print_r<hr /><h3><time class="entryDate" title="2010-07-01T17:42:49-05:00" datetime="2010-07-01T17:42:49-05:00">Jul. 1, 2010</time></h3>Event Modification Started<hr /><h3><time class="entryDate" title="2010-06-30T15:10:22-05:00" datetime="2010-06-30T15:10:22-05:00">Jun. 30, 2010</time></h3>Initial version of SimpleCalendar<hr /></div>
<p>SimpleCalendar is a very simple PHP calendar class written to be easy to use and flexible.</p>
<p>It includes basic event logic and is made to be modified to your particular needs.</p>
<p><small>More Details Soon</small></p>

<h4>Sample Usage</h4>
<p><pre style="width:52%">&lt;?php
require_once('SimpleCalendar.php');
$calendar = new SimpleCalendar();
$calendar-&gt;addDailyHtml( 'Sample Event', 'today', 'tomorrow' );
$calendar-&gt;show(true);
?&gt;</pre></p>

<h4>Example Calendar</h4>


<p><a http://donatstudios.com/Array target="_blank">Click here for the Github repository.</a></p>

<table class="datatable" style="width: 100%" cellpadding="0" cellspacing="0">
<tr><th align="left">Build</th><th align="left">Date</th><th align="left">Message</th></tr><tr class="odd"><td align="left">v.1<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-07-12T14:32:34-05:00" datetime="2010-07-12T14:32:34-05:00">Jul. 12, 2010</time></td><td align="left"><small>Merge branch 'master' of github.com:donatj/SimpleCalendar</small></td></tr></table>
]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/JDZoom</guid>
      <title>JDZoom</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Wed, 10 Nov 2010 23:53:32 CST</pubDate>
      <link>http://donatstudios.com/JDZoom</link>
      <description><![CDATA[<div class="GithubFeed"><h2>Recent Activity</h2><h3><time class="entryDate" title="2010-10-25T11:26:30-05:00" datetime="2010-10-25T11:26:30-05:00">Oct. 25, 2010</time></h3>Fixed an issue with cross domain images<hr /><h3><time class="entryDate" title="2010-10-08T09:34:28-05:00" datetime="2010-10-08T09:34:28-05:00">Oct. 8, 2010</time></h3>Fixed a regression where selector would only accept strings<hr /><h3><time class="entryDate" title="2010-10-07T23:58:52-05:00" datetime="2010-10-07T23:58:52-05:00">Oct. 7, 2010</time></h3>Restructured Repo per MooTools Forge requirements<hr />Updated README.md<hr />Added Options:<br />
<br />
Magnified Position Option Added<br />
options: fixed/float<br />
<br />
Cancel Click Option Added<br />
boolean, prevents default on an images anchor<br />
<br />
Misc Code Cleanup...<br />
<br />
Fixed &quot;endless.com&quot; style added<br />
<br />
index.html demo's updated - shows many different<br />
options and settings in action.<hr />Added escaping to css url() calls to prevent problems with images with<br />
spaces in file names.<hr />Large Rework of Functionality<br />
- Chrome compatability added<br />
- Zoom box to magnified result math corrected<br />
- Image preloaded<br />
- Div now hovers over image rather than replacing<br />
- Selector option added allowing an element, array of elements,<br />
or a string selector to be passed.<br />
- Internet Explorer Compatability fixes.<hr /><h3><time class="entryDate" title="2010-06-07T11:22:08-05:00" datetime="2010-06-07T11:22:08-05:00">Jun. 7, 2010</time></h3>README.md and .gitignore added<hr />Initial Commit<hr /></div>

<p>JDZoom is a MooTools powered hover zoom / magnifier similarly styled to the one featured on Endless.com.</p>
<p>It is supported by IE6+, Firefox 2.5+, Safari 2+ and Chrome</p>
<p>It does not interfere with click though, such it can be used in conjunction with almost any lightbox. In fact by altering the selector when you instantiate it, most lightboxes can be extended with JDZoom without touching the HTML at all. See the <a http://donatstudios.com/Array target="_blank">advanced demonstration</a> for more details.</p>
<p>JDZoom requires MooTools, and is Compatible with 1.2.5+ and 1.3+</p>
<p>It <strong>does not require</strong> any components of <i>MooTools More</i>.</p>

<p><a http://donatstudios.com/Array target="_blank">Click here for the Github repository.</a></p>

<fieldset style="width:300px"><legend>Demonstration</legend>
<a rel="jdzoom_fixed" http://donatstudios.com/Array  title="Sakakibara Onsen, I've been naked here"><img http://donatstudios.com/Array width="300" /></a>
<div style="text-align: center"><small><a http://donatstudios.com/Array>View Advanced Demonstration</a></small></div>
</fieldset>
<h2>Example Source</h2>
<pre><code>
&lt;html&gt;
&lt;head&gt;
	&lt;link http://donatstudios.com/Arrayhttps://github.com/donatj/jdzoom/blob/master/Demo/css/jdzoom.css">css/jdzoom.css</a>" rel="stylesheet" type="text/css" /&gt;
	&lt;script src=&quot;<a http://donatstudios.com/Array target="_blank">js/mootools.js</a>&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	&lt;script src=&quot;<a http://donatstudios.com/Array target="_blank">js/jdzoom.js</a>&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot;&gt;<br>	window.addEvent('load',function() { <br>		var jdz = new JDZoom();<br>	});<br>	&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;a rel="jdzoom" http://donatstudios.com/Arrayhttp://donatstudios.com/assets/18/Demo/images/venus.jpg" target="_blank">images/venus.jpg</a>"&gt;&lt;img http://donatstudios.com/Arrayhttp://donatstudios.com/assets/18/Demo/images/venus_thumb.jpg" target="_blank">images/venus_thumb.jpg</a>" /&gt;&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>

<table class="datatable" style="width: 100%" cellpadding="0" cellspacing="0">
<tr><th align="left">Build</th><th align="left">Date</th><th align="left">Message</th></tr><tr class="odd"><td align="left">v0.9.1<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-10-07T22:21:32-05:00" datetime="2010-10-07T22:21:32-05:00">Oct. 7, 2010</time></td><td align="left"><small>Added Options:<br />
<br />
Magnified Position Option Added<br />
options: fixed/float<br />
<br />
Cancel Click Option Added<br />
boolean, prevents default on an images anchor<br />
<br />
Misc Code Cleanup...<br />
<br />
Fixed "endless.com" style added<br />
<br />
index.html demo's updated - shows many different<br />
options and settings in action.</small></td></tr><tr class=""><td align="left">v0.9<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-10-07T18:47:12-05:00" datetime="2010-10-07T18:47:12-05:00">Oct. 7, 2010</time></td><td align="left"><small>Large Rework of Functionality<br />
- Chrome compatability added<br />
- Zoom box to magnified result math corrected<br />
- Image preloaded<br />
- Div now hovers over image rather than replacing<br />
- Selector option added allowing an element, array of elements,<br />
or a string selector to be passed.<br />
- Internet Explorer Compatability fixes.</small></td></tr><tr class="odd"><td align="left">v0.1<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-06-07T11:22:08-05:00" datetime="2010-06-07T11:22:08-05:00">Jun. 7, 2010</time></td><td align="left"><small>README.md and .gitignore added</small></td></tr></table>

]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/XML_Excel_Exporter</guid>
      <title>XML Excel Exporter</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Wed, 10 Nov 2010 16:54:58 CST</pubDate>
      <link>http://donatstudios.com/XML_Excel_Exporter</link>
      <description><![CDATA[<div class="GithubFeed"><h2>Recent Activity</h2><h3><time class="entryDate" title="2010-10-15T23:46:59-05:00" datetime="2010-10-15T23:46:59-05:00">Oct. 15, 2010</time></h3>XSpreadsheet dies after outputting the spreadsheet now, preventing corruption<hr /><h3><time class="entryDate" title="2010-02-18T13:05:58-06:00" datetime="2010-02-18T13:05:58-06:00">Feb. 18, 2010</time></h3>Repository Restructured<br />
-Working Corpus now in Source Folder<br />
-`Scripts` folder added, includes database dump batch, and README.md HTML viewer<br />
-`Local` folder added, for testing use with local database connections, etc<br />
<br />
Documentation<br />
-Finally! Created an initial README.md<br />
-TODO moved from includes folder into root<hr /></div>

<p>This simple class allows you via PHP to export an XML Spreadsheet compatible with all versions of Excel 2003 and up.</p>

<p>The files generated will work with versions of Office 2003 and up. It is considered production safe, and is currently in use in a fair number of production sites.<p>

<p>Unlike CSV or HTML Table exports, <strong>you can have multiple worksheets of data!</strong> A sheets data can be added to the spreadsheet either by a MySQL query resource or as a 2 dimensional array.</p>

<h3>Known bugs:</h3>
<ul>
	<li>Office 2007/2010 bark about XLS file extensions despite refusing to open XML file extensions downloaded from the internet. (Anyone know a solution?)</li>
	<li>DOMDocument incorrectly converts/removes non-printable/low range characters (eg: &amp;#10;).</li>
</ul>

<h3>Limitations:</h3>
<ul>
	<li>File Format is not supported by:
	<ul>
		<li>Open Office</li>
		<li>Google Documents</li>
		<li>Microsoft Office Live</li>
	</ul>
	</li>
</ul>

<h2>MySQL Example</h2>
<pre>require('includes/classes/XSpreadsheet.php');
$spread = new XSpreadsheet($fname)
$spread-&gt;AddWorksheet('Products', mysql_query(&quot;Select * From products&quot;))
	-&gt;AddWorksheet('Categories', mysql_query(&quot;Select * From categories&quot;))
	-&gt;Generate()-&gt;Send();
</pre>

<h2>Array Example</h2>
<pre>require('includes/classes/XSpreadsheet.php');
$data = array(
	array( 'Column 1', 'Column 2', 'Column 3' ),
	array( 1, 2, 3 ),
);
 
$spread = new XSpreadsheet($fname)
$spread-&gt;AddWorksheet('Awesome Sheet', $data )
	-&gt;Generate()-&gt;Send();
</pre>

<a title="Click Here to Download" http://donatstudios.com/Array ><button type="button" >Click Here to Download</button></a>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/No_App_P1_PhpED</guid>
      <title>There Isn't an App for&#x2026; - Part 1: PhpED</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Thu, 09 Dec 2010 10:25:44 CST</pubDate>
      <link>http://donatstudios.com/No_App_P1_PhpED</link>
      <description><![CDATA[<h2>&ldquo;There Isn't an App For That&rdquo; - Windows Apps I haven't been able to replace in Mac OS X</h2>
<p>For a very long time I was a Windows guy, I <em>was once</em> a DOS guy. I switched nearly exclusively to Mac for my home use about 4 years ago. I&rsquo;ve been very happy with it. Its stable, well engineered, and - my favorite part of all - consistent. Yet, in this time there remain a few applications I cannot seem to replace.</p>
<h3><a http://donatstudios.com/Array>Nusphere PhpED</a></h3>
<p> I am a PHP Developer by trade, and PhpED for my money is by far the best development environment for the serious PHP developer. When I do develop on the Mac platform it is usually split between two applications &ndash; Coda and TextMate. They are fantastic text editors, don&rsquo;t misunderstand, but when you are developing highly classed applications a strong IDE becomes highly desirable. PhpED&rsquo;s IntelliSense style PHP auto completion is <strong>on par</strong> with and in some ways <strong>surpasses</strong> Visual Studios.</p>
<p>Applications like Dreamweaver, Coda, TextMate and Espresso by comparison provide very basic auto completion. Zend Studio, Aptana Studio and other Eclipse based solutions have varying qualities of auto completion, but are awkward due to Eclipses generality and slow and visually out of water due to being built on Java. Komodo comes the closest, but can be very slow at times. Weighing in at $299 its pricetag is also heavy.</p>
<p>To give you in an example, in my CorpusPHP Framework the user class is built specifically to be extended for the sites particular needs. The login class therefore has a member instance of <em>whatever</em> type of object extending user you might have. This member is dynamically set as an instance and therefore type cannot be determined by <em>most</em> editors and auto completion will not work.&nbsp; PhpED on the other hand has a solution. This brings me to my favorite PhpED feature - deep phpDocumentor integration.</p>
<pre>class Login {<br />
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;* Object that holds the user object, brought over from the session
&nbsp;&nbsp;&nbsp;&nbsp;* @var User
&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public $user;

&nbsp;&nbsp;&nbsp;&nbsp;&hellip;&nbsp;&hellip;&nbsp;&hellip;<br />
}</pre>
<p>The above code snippet shows the user member of the login class. It can be any type of user, for instance admin or limited. It will though be inherently be something that extends the user object.&nbsp; Using phpDocumentor syntax here we imply that the type is a <em>user</em> and since PhpED is smart, it auto completes based on this.&nbsp; If you are unfamiliar with phpDocumentor syntax you should <a http://donatstudios.com/Array target="_blank">read up on it</a>, and begin marking your PHP up in this standardized syntax.</p>
<p> <img http://donatstudios.com/Array alt="Php Autocomplete" /></p>
<p> PhpED takes this integration further and will show descriptions of methods and functions as well as their parameters and return values based on their inline phpDocumentor documentation.</p>
<p> <img http://donatstudios.com/Array alt="PhpED phpDoc description" /></p>
<p> While auto complete is the PhpED killer feature in my book, it has many other excellent features.</p>
<p>&nbsp;Its internal debugger&nbsp; is second to none, and requires <em>no</em> setup unlike other debuggers. It installs its own copies of Apache and PHP 4 &amp; PHP 5.2 or 5.3 which it uses to debug. The debugger can output to an internal version of IE or Mozilla or any external browser. Its quite configurable, everything you would expect like ability to set $_GET, $_POST, etc variables, break points, runtime analysis.</p>
<p>Some smaller features I personally enjoy are for instance:</p>
<ul>
	<li>To-Do list shows you all the todo&rsquo;s throughout your project.</li>
	<li>Continually improving, high quality CSS/HTML auto completion.</li>
	<li>The ability to set a default character set on a per-project basis</li>
	<li>Non-Ascii range characters show up dark blue in variable and function names, making them obvious &ndash; which is particularly helpful when working on code from a Cyrillic coder whereas &Alpha; (Alpha) and A are <em>visually</em> identical but entirely different characters.</li>
	<li>Great support &ndash; Support will work with you to fix a problem.</li>
</ul>
<h2>Update 7/7/2011</h2>
<p>The dark PhpED Theme I use is now available <a http://donatstudios.com/Array>here for PhpED 5 and 6</a>.</p>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/CorpusPHP</guid>
      <title>CorpusPHP</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Wed, 02 Dec 2009 15:21:04 CST</pubDate>
      <link>http://donatstudios.com/CorpusPHP</link>
      <description><![CDATA[<div class="GithubFeed"><h2>Recent Activity</h2><h3><time class="entryDate" title="2011-08-31T10:22:16-05:00" datetime="2011-08-31T10:22:16-05:00">Aug. 31, 2011</time></h3>Edited README.md via GitHub<hr />Merge branch 'master' of github.com:donatj/CorpusPHP<hr /><h3><time class="entryDate" title="2011-08-04T08:53:28-05:00" datetime="2011-08-04T08:53:28-05:00">Aug. 4, 2011</time></h3>Cache class made to autocleanup on construct instead of just on set<hr /><h3><time class="entryDate" title="2011-06-03T23:55:01-05:00" datetime="2011-06-03T23:55:01-05:00">Jun. 3, 2011</time></h3>concats in search query changed to concat_ws(' ' to prevent null row issues.<hr /><h3><time class="entryDate" title="2011-05-29T01:24:22-05:00" datetime="2011-05-29T01:24:22-05:00">May. 29, 2011</time></h3>Corrected a longstanding issue where the homepage wouldn't work on certain servers<hr /><h3><time class="entryDate" title="2011-05-12T00:13:17-05:00" datetime="2011-05-12T00:13:17-05:00">May. 12, 2011</time></h3>Merge branch 'master' into autoload<hr />Merge branch 'master' of github.com:donatj/CorpusPHP<hr /><h3><time class="entryDate" title="2011-05-10T16:14:32-05:00" datetime="2011-05-10T16:14:32-05:00">May. 10, 2011</time></h3>Merge branch 'master' of github.com:donatj/CorpusPHP<hr />Trebuchet MS is sooo 2009<hr />head added to categories allowing things to be placed in the head tag<hr />&lt;br clear=&quot;all&quot;/&gt;' =&gt; &lt;br style=&quot;clear: both;&quot;/&gt; and other html5 complaints<hr /><h3><time class="entryDate" title="2011-03-30T00:19:53-05:00" datetime="2011-03-30T00:19:53-05:00">Mar. 30, 2011</time></h3>Made pull the *name* of the page as a last ditch effort before pulling the default meta title<hr /><h3><time class="entryDate" title="2011-03-20T13:14:03-05:00" datetime="2011-03-20T13:14:03-05:00">Mar. 20, 2011</time></h3>Slight cleanup of displayImage.php<hr /><h3><time class="entryDate" title="2011-03-18T23:53:31-05:00" datetime="2011-03-18T23:53:31-05:00">Mar. 18, 2011</time></h3>Autoloader slightly improved<hr />Class =&gt; class in User dbo<hr />Vert slight cleanup of includes/classes/Database.php<hr /><h3><time class="entryDate" title="2011-03-01T17:59:31-06:00" datetime="2011-03-01T17:59:31-06:00">Mar. 1, 2011</time></h3>Autoloader functionality roughed in.<hr /><h3><time class="entryDate" title="2011-02-24T16:11:37-06:00" datetime="2011-02-24T16:11:37-06:00">Feb. 24, 2011</time></h3>Pagnation Class Updated<hr /><h3><time class="entryDate" title="2011-01-28T12:33:50-06:00" datetime="2011-01-28T12:33:50-06:00">Jan. 28, 2011</time></h3>Removed up-to 75 unnecessary queries<hr />Last.fm module upgraded to 2.0 API<hr />Improvments to button styling<hr />Layout upgrades from Donat Studios merged in<hr />MooTools switched to pull from Google API, upgraded to 1.3<hr /><h3><time class="entryDate" title="2011-01-05T14:46:24-06:00" datetime="2011-01-05T14:46:24-06:00">Jan. 5, 2011</time></h3>fe:: methods changed to accept array as $value and then use the name as key<br />
fe:: documentation updated<hr /><h3><time class="entryDate" title="2010-12-21T00:18:32-06:00" datetime="2010-12-21T00:18:32-06:00">Dec. 21, 2010</time></h3>Optional $seperator paramter added to the breadcrumb generator.<hr />Fixed a small issue with the background streach on the button script.<hr />Button generated updated to support alpha blended base pngs<br />
<br />
Signed-off-by: Jesse Donat &lt;donatj@gmail.com&gt;<hr /><h3><time class="entryDate" title="2010-11-16T18:09:02-06:00" datetime="2010-11-16T18:09:02-06:00">Nov. 16, 2010</time></h3>nl2br added to comments so newlines break.<hr /><h3><time class="entryDate" title="2010-11-15T14:38:21-06:00" datetime="2010-11-15T14:38:21-06:00">Nov. 15, 2010</time></h3>Updated uinfo query to prevent case insensitivity<hr /><h3><time class="entryDate" title="2010-11-13T01:39:32-06:00" datetime="2010-11-13T01:39:32-06:00">Nov. 13, 2010</time></h3>Fixed a sorting issue with Comments<hr /><h3><time class="entryDate" title="2010-10-16T12:17:28-05:00" datetime="2010-10-16T12:17:28-05:00">Oct. 16, 2010</time></h3>Updated Version/Date in index.php comments<hr />Modules Added<br />
- Github Feed<br />
- Github Tags<br />
- iFrame<br />
- Tag Cloud<hr /><h3><time class="entryDate" title="2010-10-15T23:46:59-05:00" datetime="2010-10-15T23:46:59-05:00">Oct. 15, 2010</time></h3>XSpreadsheet dies after outputting the spreadsheet now, preventing corruption<hr />Merge branch 'master' of github.com:donatj/CorpusPHP<hr /><h3><time class="entryDate" title="2010-10-13T16:46:55-05:00" datetime="2010-10-13T16:46:55-05:00">Oct. 13, 2010</time></h3>RSS Feed Updates<br />
- all src/href tags ran through href()<br />
- iframe/script/style tags stripped<br />
- configuration option for image added<hr /></div>
<p>CorpusPHP is setting out to be a world class PHP Framework. The aim is simple, to provide encapsulation, modularization, and helpful tools, all without changing the way you write PHP.</p>
<p><strong>Project Information, documentation, and a timeline for the first release available  availble soon</strong></p>
<p>Nightly's available at <a http://donatstudios.com/Array target="_new">GitHub</a>, or download the latest milestone below.
<table class="datatable" style="width: 100%" cellpadding="0" cellspacing="0">
<tr><th align="left">Build</th><th align="left">Date</th><th align="left">Message</th></tr><tr class="odd"><td align="left">v0.99<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2011-05-12T00:13:17-05:00" datetime="2011-05-12T00:13:17-05:00">May. 12, 2011</time></td><td align="left"><small>Merge branch 'master' into autoload</small></td></tr><tr class=""><td align="left">v0.981<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-12-21T00:18:32-06:00" datetime="2010-12-21T00:18:32-06:00">Dec. 21, 2010</time></td><td align="left"><small>Optional $seperator paramter added to the breadcrumb generator.</small></td></tr><tr class="odd"><td align="left">v0.98<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-08-31T11:14:23-05:00" datetime="2010-08-31T11:14:23-05:00">Aug. 31, 2010</time></td><td align="left"><small>Arial Replaced with Vera, references to helvetica removed</small></td></tr><tr class=""><td align="left">v0.92<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-05-14T12:42:07-05:00" datetime="2010-05-14T12:42:07-05:00">May. 14, 2010</time></td><td align="left"><small>Basic SSL support added</small></td></tr><tr class="odd"><td align="left">v0.9<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-02-18T13:05:58-06:00" datetime="2010-02-18T13:05:58-06:00">Feb. 18, 2010</time></td><td align="left"><small>Repository Restructured<br />
-Working Corpus now in Source Folder<br />
-`Scripts` folder added, includes database dump batch, and README.md HTML viewer<br />
-`Local` folder added, for testing use with local database connections, etc<br />
<br />
Documentation<br />
-Finally! Created an initial README.md<br />
-TODO moved from includes folder into root</small></td></tr><tr class=""><td align="left">v0.85<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-02-08T14:56:27-06:00" datetime="2010-02-08T14:56:27-06:00">Feb. 8, 2010</time></td><td align="left"><small>Cache.php<br />
-Major rewrite of cache handling - now requires an instance<br />
<br />
Configuration.php<br />
-Added module option to constructor to interface Corpus class and module namespace<br />
<br />
Corpus.php<br />
-New __premeta function pulls the first scans data into the module namespace<br />
-$_cache and $_config added to the __load function, vis-à-vis the module namespace<br />
<br />
Modules<br />
-Updated for new 'name' meta attribute, 'call' depricated, 'callable' boolean added<br />
--Button.php<br />
--Crux.php<br />
--FlashLoader.php<br />
--FlickrFeed.php<br />
--LastFM.php<br />
--TwitterFeed.php<br />
-Configuration options added<br />
--FlickrFeed.php<br />
--LastFM.php<br />
--TwitterFeed.php</small></td></tr><tr class="odd"><td align="left">v0.7<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2010-02-03T16:54:54-06:00" datetime="2010-02-03T16:54:54-06:00">Feb. 3, 2010</time></td><td align="left"><small>functions/general.php<br />
	-Updated nempty for PHP 5.3 compatibility (Weird casting bug)<br />
	-Removed some unused, commented out, functions</small></td></tr><tr class=""><td align="left">v0.1<br /><small><a http://donatstudios.com/Array>Download</a></small></td><td align="left"><time class="entryDate" title="2009-12-02T11:07:00-06:00" datetime="2009-12-02T11:07:00-06:00">Dec. 2, 2009</time></td><td align="left"><small>Initial CorpusPHP Alpha Release</small></td></tr></table>
]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/Andrew_Gross</guid>
      <title>The Work of Andrew Gross</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Sat, 28 Nov 2009 15:21:09 CST</pubDate>
      <link>http://donatstudios.com/Andrew_Gross</link>
      <description><![CDATA[Details to Come]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/Donat_Studios_Launches</guid>
      <title>Donat Studios Officially Launches</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Mon, 26 Oct 2009 20:45:28 CST</pubDate>
      <link>http://donatstudios.com/Donat_Studios_Launches</link>
      <description><![CDATA[<p>After much ado, Donat Studios is finally live!</p>
<p>There are a few things left to complete. Eventually setting up the documentation and public git repository for CorpusPHP will certainly take up a fair amount of time. I'm still not quite sure what to put in my portfolio, I was thinking of for the time being just throwing a bunch of my sketches in there.</p>
<p>My reasoning and goals behind this site are slightly different than my other sites. More than anything I wanted a place where I could rant about everything web related. I have strong opinions on many topics, and where Oasisband.net is good for movies and politics, and PHPStandards is pretty much just raw anger directed at Zend, and my live journal is for my personal life. Donat Studios on the other hand will allow me to express my thoughts on web development, databases, html, php, ajax, design, basically everything I do at work.</p>
<p>Where does the name &quot;Donat Studios&quot; come from? I was getting some photos printed by a great place in St. Paul, &quot;White House Custom Color&quot; and they needed to know the name of my studio. I didn't have a studio, so I quickly made up &quot;Donat Studios&quot;. Later, I realized I liked the name, and it stuck.</p>
<p>Here's wishing my newest domain luck!</p>]]></description>
    </item>
    <item>
      <guid>http://donatstudios.com/JSONP</guid>
      <title>The Sad Truth About and Reasoning Behind JSONP</title>
      <author>noreply@donatstudios.com(Donat Studios)</author>
      <pubDate>Mon, 12 Oct 2009 16:36:35 CST</pubDate>
      <link>http://donatstudios.com/JSONP</link>
      <description><![CDATA[<p>I don&rsquo;t want anyone take this the wrong way.&nbsp; I am having a torrid affair with JSON. It is so much simpler to parse than XML, and is an all around exceptional way to represent data. I have one caveat though, and that is &ldquo;JSON with Padding&rdquo; or &ldquo;JSONP&rdquo; as it goes by.</p>
<p>While building <em>this site</em> I was trying to bring in images from my Flickr account, as you may have noticed. Building the module in PHP, I basically ran <em>file_get_contents</em> on the feeds url and passed that directly into json_decode. On print_r&rsquo;ing the results, it was null. It had failed.&nbsp; As a test I echoed the result of the file_get_contents to see what was up. It was succeeding at retrieving the feed, and at a glance it looked like JSON, yet it was failing to parse. I knew something was up. </p>
<p> Here is an example result set:</p>
<pre>jsonFlickrFeed({<br />                &quot;title&quot;: &quot;Uploads from donatj&quot;,<br />                &quot;link&quot;: &quot;http://www.flickr.com/photos/donatj/&quot;,<br />                &quot;description&quot;: &quot;&quot;,<br />                &quot;modified&quot;: &quot;2009-05-31T08:24:46Z&quot;,<br />                &quot;generator&quot;: &quot;http://www.flickr.com/&quot;,<br />                &quot;items&quot;: [<br />           {<br />                        &quot;title&quot;: &quot;STP81353&quot;,<br />                        &quot;link&quot;: &quot;http://www.flickr.com/photos/donatj/3581174864/&quot;,<br />                        &quot;media&quot;: {&quot;m&quot;:&quot;http://farm4.static.flickr.com/3568/3581174864_be1a44764e_m.jpg&quot;},<br />                        &quot;date_taken&quot;: &quot;2009-03-30T19:10:34-08:00&quot;,<br />                        &quot;description&quot;: &quot;&lt;p&gt;&lt;a href=\&quot;http://www.flickr.com/people/donatj/\&quot;&gt;donatj&lt;\/a&gt; posted a photo:&lt;\/p&gt; &lt;p&gt;&lt;a href=\&quot;http://www.flickr.com/<br />photos/donatj/3581174864/\&quot; title=\&quot;STP81353\&quot;&gt;&lt;img src=\&quot;http://farm4.static.flickr.com/3568/3581174864_be1a44764e_m.jpg\&quot; width=\&quot;180\&quot; height=\&quot;240\&quot; alt=\&quot;S<br />TP81353\&quot; /&gt;&lt;\/a&gt;&lt;\/p&gt; &quot;,<br />                        &quot;published&quot;: &quot;2009-05-31T08:24:46Z&quot;,<br />                        &quot;author&quot;: &quot;nobody@flickr.com (donatj)&quot;,<br />                        &quot;author_id&quot;: &quot;30444376@N08&quot;,<br />                        &quot;tags&quot;: &quot;&quot;<br />           }<br />        ]<br />})</pre><p>On further examination I noticed, as you should have noted, the data is wrapped in a function.&nbsp; My first thought was that this violates the <a http://donatstudios.com/Array>JSON Specification</a>, so I immediately tweeted about how silly it was for Flickr to have an invalid JSON feed when their parent company Yahoo employs Douglas Crockford, the creator of JSON. I soon received a response from a colleague informing me that this was JSONP. He explained what it was, and how to use it in jQuery.</p>
<p>	It basically comes down to this:&nbsp; XMLHttpRequest will not, for cross site scripting protection, work across domains.&nbsp; Therefore, JSON cannot be directly retrieved nor parsed via JavaScript across domains.<br />
	This is where JSONP comes in.&nbsp; JSONP is essentially a regular JSON result set wrapped in a function.&nbsp; Rather than using XMLHttpRequest to retrieve the document, you dynamically attach a script tag to the page pointing the the JSONP document, which evokes a function call passing your JSON object to whatever function the JSONP is set to pass the data to, forgoing the need to eval anything.</p>
<p>I have a number of <em>criticisms</em> of this approach.</p>
<ul>
	<li>First and foremost, JSONP      is at its very heart remote code execution.&nbsp; You must have <em>absolute</em> faith not only in the intentions of the site you are      bringing the feed in from, but the security of said site as well, because      the code is in fact being <strong><em>executed</em></strong> by the browser with <em>no      chance</em> for putting regular expressions or other such safety mechanisms      in place. This makes your site and visitors <em>wide open</em> to <strong>any and      all</strong> malicious code a hacker may plant in the feed.</li>
	<li>JSONP is a language specific      data type. What I mean by this is that JSONP is designed <em>for</em> <strong>JavaScript</strong>, and even then <strong>strictly      in the context of a web browser</strong>.&nbsp;      There is no <em>need, none,</em> for JSONP anywhere else or in any other language (PHP, ASP.Net, Ruby on      Rails). Making a <em>feed</em> in a      language specific format is inherently in <em>bad form</em>.</li>
	<li>Adding to the last point,      other languages currently cannot naturally parse JSONP. As I ran into in      PHP, it is <em>not valid JSON</em> and      json_decode will not handle it.&nbsp; My colleagues      answer was to write a regular expression to remove the function, but this      is at best a hack.</li>
	<li>Mixing function and data      goes in the face of <em>separation of concerns.</em> You&rsquo;ve got logic in your data, you&rsquo;ve got data in your logic.&nbsp; Bad form, good sir, bad form.</li>
</ul>
<p>JSONP is in many cases an unsafe practice, and more over its just <em>evil</em>. It is a necessary evil in some cases, but evil none the less.</p>
<p>There is at <em>least</em> one<strong> safe alternative</strong> to JSONP, and I&rsquo;m willing to wager more. The simplest solution provided you have access to server side code is to download, sanitize, optionally cache, and finally pass locally any remote JSON to the client rather than having the clients machine directly load the feed. Yes, this is added overhead on your side, bur for much added <strong>security</strong>.</p>
<p>If nothing else, it is up to you to weigh the risks and benefits before blindly using JSONP.</p>]]></description>
    </item>
  </channel>
</rss>


