<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title>DrSlump @ Pollinimini.net</title>
  
  <link href="http://pollinimini.net" />
  <updated>2011-02-08T21:52:45+01:00</updated>
  <id>http://pollinimini.net/</id>
  <author>
    <name>Iván -DrSlump- Montes</name>
    <email>drslump@pollinimini.net</email>
  </author>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/drslump" /><feedburner:info uri="drslump" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title>Zend Framework InlineScript helper hack</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/p6Aw2A8EnZU/zend-framework-inlinescript-helper-hack" />
    <updated>2011-02-08T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/zend-framework-inlinescript-helper-hack</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Pepe -_blacky_- Jiménez has been kind enough to act as special guest in this blog and write about a &lt;em&gt;hack&lt;/em&gt; he found, when including Javascript chunks into PHP files, while using &lt;a href='http://framework.zend.com'&gt;Zend Framework&lt;/a&gt;&amp;#8217;s &lt;a href='http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.inlinescript'&gt;InlineScript&lt;/a&gt; view helper.&lt;/p&gt;

&lt;p&gt;If you are looking for a talented web frontend programmer I can only speak good words about this bloke.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id='why_this_hack'&gt;Why this hack?&lt;/h2&gt;

&lt;p&gt;Syntax highlighting is essential for developers. If you are familiar with &lt;a href='http://framework.zend.com'&gt;Zend Framework&lt;/a&gt; you will know that &lt;a href='http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.inlinescript'&gt;InlineScript&lt;/a&gt; view helper doesn&amp;#8217;t need the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. The reason is simple, that tag is automatically included at the view rendering stage. There is one big disadvantage however when you are developing in your favorite IDE&amp;#8230; No syntax highlighting for your JavaScript piece of code.&lt;/p&gt;

&lt;p&gt;When I noticed that, I searched for a solution at Google. No luck this time&amp;#8230; So I started thinking how to solve this issue. As far as I know, IDEs detect JavaScript language in source files thanks to the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag, so that should be a good start. If we could find a way to keep the tag in the source file and remove it before rendering it the problem would disappear.&lt;/p&gt;

&lt;h2 id='how_it_works'&gt;How it works?&lt;/h2&gt;

&lt;p&gt;The &lt;a href='http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.inlinescript'&gt;InlineScript&lt;/a&gt; inherits from &lt;a href='http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.headscript'&gt;HeadScript&lt;/a&gt; who is responsible for introducing JavaScript content (literal source code or file). Taking a look at the &lt;a href='http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.headscript'&gt;HeadScript&lt;/a&gt; &lt;code&gt;__call&lt;/code&gt; method, the &lt;code&gt;createData&lt;/code&gt; function is the best candidate to solve this tag issue. If we look at Zend Framework&amp;#8217;s source code, the 3rd parameter is the one containing our JavaScript code (potentially including the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag).&lt;/p&gt;

&lt;p&gt;Once we have this function located is very easy to remove the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. We just need to create a custom view helper extending Zend Framework&amp;#8217;s one in order to override the &lt;code&gt;createData&lt;/code&gt; method. At this point take a look at the source code below to see how it works.&lt;/p&gt;

&lt;p&gt;I hope this post will prove useful to other developers who have been in the same situation as me.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Don&amp;#8217;t forget that custom view helpers prefix and paths have to be properly configured in your application to be automatically loaded and used.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id='code'&gt;Code&lt;/h2&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Remove &amp;lt;script&amp;gt; tags&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @author      Jose Luis Jiménez &amp;lt;jljc.work@gmail.com&amp;gt;&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Pepe_Zend_View_Helper_InlineScript&lt;/span&gt; &lt;span class='k'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Zend_View_Helper_InlineScript&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;       * Create data item containing all necessary components of script&lt;/span&gt;
&lt;span class='sd'&gt;       *&lt;/span&gt;
&lt;span class='sd'&gt;       * @param  string $type&lt;/span&gt;
&lt;span class='sd'&gt;       * @param  array $attributes&lt;/span&gt;
&lt;span class='sd'&gt;       * @param  string $content&lt;/span&gt;
&lt;span class='sd'&gt;       * @return stdClass&lt;/span&gt;
&lt;span class='sd'&gt;       */&lt;/span&gt;
      &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;createData&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$type&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt; &lt;span class='nv'&gt;$attributes&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$content&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='c1'&gt;// Replace &amp;lt;script&amp;gt; tag&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$content&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='nv'&gt;$content&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;preg_replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;@^\s*&amp;lt;script[^&amp;gt;]*&amp;gt;@i&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$content&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='nv'&gt;$content&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;preg_replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;@&amp;lt;/script&amp;gt;\s*$@i&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$content&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='c1'&gt;// Call parent&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;parent&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;createData&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$type&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$attributes&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$content&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=p6Aw2A8EnZU:ArJC7RhPJI8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=p6Aw2A8EnZU:ArJC7RhPJI8:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=p6Aw2A8EnZU:ArJC7RhPJI8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=p6Aw2A8EnZU:ArJC7RhPJI8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=p6Aw2A8EnZU:ArJC7RhPJI8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/p6Aw2A8EnZU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/zend-framework-inlinescript-helper-hack</feedburner:origLink></entry>
  
  <entry>
    <title>PHP post_max_size issue</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/CwAMh6rYnY0/php-post-max-size" />
    <updated>2010-08-03T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/php-post-max-size</id>
    <content type="html">&lt;p&gt;PHP&amp;#8217;s ability to manage uploaded files has always left mixing feelings in me, on one hand it&amp;#8217;s really trivial to implement file upload functionality on PHP scripts but in the other, managing big files uploads (just anything above a couple megabytes) is far from reliable.&lt;/p&gt;

&lt;p&gt;Recently a couple solutions became popular to implement &lt;em&gt;progressive uploads&lt;/em&gt; in PHP, &lt;a href='http://pecl.php.net/package/uploadprogress'&gt;PECL&amp;#8217;s uploadprogress extension&lt;/a&gt; and recent &lt;a href='http://www.php.net/manual/es/apc.configuration.php#ini.apc.rfc1867'&gt;APC&lt;/a&gt; versions. But anyway, the default PHP behaviour when uploading a file is to wait until it&amp;#8217;s been fully transferred to the server before executing the php script.&lt;/p&gt;

&lt;p&gt;This design decision from the PHP folks greatly simplifies the most common case, since you always get the full file when your PHP code runs, but also means that &lt;em&gt;big&lt;/em&gt; files can cause some serious trouble. To defend itself, PHP has a few ini options that tune its ability to work with big files.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;upload_max_filesize&lt;/code&gt; tells PHP the maximum size an uploaded file can have, files bigger will be reported as an error in the &lt;code&gt;$_FILES&lt;/code&gt; array. &lt;code&gt;max_input_time&lt;/code&gt; control the maximum time PHP can spend receiving data from the client, this is important because if you have many visitors with slow connections (or a malevolent attacker) a lot of PHP processes will be idling in memory collecting data slowly, consuming your server resources and potentially provoking your server to become unresponsive. Finally, we have &lt;code&gt;post_max_size&lt;/code&gt;, which is a bit tricky, it limits the maximum amount of data a request from the client can hold. The tricky part is that if that limit is reached PHP won&amp;#8217;t error out or signal the problem anyhow to your script, instead it will continue normal script execution but won&amp;#8217;t populate &lt;code&gt;$_POST&lt;/code&gt; or &lt;code&gt;$_FILES&lt;/code&gt; superglobals, leaving them empty.&lt;/p&gt;

&lt;p&gt;So if your &lt;code&gt;post_max_size&lt;/code&gt; is set to 2Mb and a client uploads a 3Mb file, nor &lt;code&gt;$_POST&lt;/code&gt; neither &lt;code&gt;$_FILES&lt;/code&gt; will have any content. Even if you set your &lt;code&gt;upload_max_filesize&lt;/code&gt; to 2Mb or below, if size of the file (or files) is bigger you will find yourself with those superglobals empty.&lt;/p&gt;

&lt;p&gt;There is however a way to detect this condition, like shown in the following code snippet.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;in_array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$_SERVER&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$_POST&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$_FILES&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

    &lt;span class='c1'&gt;// Get maximum size and meassurement unit&lt;/span&gt;
    &lt;span class='nv'&gt;$max&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;ini_get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;post_max_size&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nv'&gt;$unit&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$max&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nb'&gt;is_numeric&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$unit&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nv'&gt;$max&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$max&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='c1'&gt;// Convert to bytes&lt;/span&gt;
    &lt;span class='k'&gt;switch&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;strtoupper&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$unit&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;G&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
        &lt;span class='nv'&gt;$max&lt;/span&gt; &lt;span class='o'&gt;*=&lt;/span&gt; &lt;span class='m'&gt;1024&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
      &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
        &lt;span class='nv'&gt;$max&lt;/span&gt; &lt;span class='o'&gt;*=&lt;/span&gt; &lt;span class='m'&gt;1024&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
      &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
        &lt;span class='nv'&gt;$max&lt;/span&gt; &lt;span class='o'&gt;*=&lt;/span&gt; &lt;span class='m'&gt;1024&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='c1'&gt;// Assert the content length is within limits&lt;/span&gt;
    &lt;span class='nv'&gt;$length&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$_SERVER&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;CONTENT_LENGTH&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$max&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='nv'&gt;$length&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;throw&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;Exception&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Maximum content length size (&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='nv'&gt;$max&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;) exceeded&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;With that code in place you can gracely detect the issue and act accordingly by showing the user an error page explaining what just happened for example.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=CwAMh6rYnY0:2ByGaBWhlkE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=CwAMh6rYnY0:2ByGaBWhlkE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=CwAMh6rYnY0:2ByGaBWhlkE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=CwAMh6rYnY0:2ByGaBWhlkE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=CwAMh6rYnY0:2ByGaBWhlkE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/CwAMh6rYnY0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/php-post-max-size</feedburner:origLink></entry>
  
  <entry>
    <title>PHP command runner class</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/6O_UaGGyD8E/php-command-runner" />
    <updated>2010-05-31T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/php-command-runner</id>
    <content type="html">&lt;p&gt;PHP offers &lt;a href='http://php.net/exec'&gt;multiple methods to execute external applications&lt;/a&gt;, for simple things they are more than enough but sometimes we need more flexibility. The following class acts as a wrapper around &lt;a href='http://php.net/proc_open'&gt;proc_open&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It implements a &lt;em&gt;fluent interface&lt;/em&gt; to ease its configuration and non-blocking pipes for stdout and stderr. The output can be obtained at the end of the program execution or incrementally by using a callback function.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='nv'&gt;$cmd&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Command&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;factory&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/usr/bin/svn&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;option&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;--username&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;drslump&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;option&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;-r&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;HEAD&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;option&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;log&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;argument&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;http://code.google.com/drslump/trunk&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;run&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getExitCode&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;echo&lt;/span&gt; &lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getStdOut&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;echo&lt;/span&gt; &lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getStdErr&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Incremental updates can be accomplished with a callback function, like in the following example (PHP 5.3+):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='nv'&gt;$cmd&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Command&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;factory&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;ls&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;setCallback&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$pipe&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;){&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$pipe&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='nx'&gt;Command&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;STDOUT&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;echo&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;STDOUT: &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$pipe&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='nx'&gt;Command&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;STDERR&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;echo&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;STDERR: &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='k'&gt;echo&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='k'&gt;NULL&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;EOF&lt;/span&gt;&lt;span class='se'&gt;\n&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;$data&lt;/span&gt;&lt;span class='se'&gt;\n&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='c1'&gt;// If we return &amp;quot;false&amp;quot; all pipes will be closed&lt;/span&gt;
        &lt;span class='c1'&gt;// return false;&lt;/span&gt;
    &lt;span class='p'&gt;})&lt;/span&gt;
    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;setDirectory&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/tmp&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;option&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;-l&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;run&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getExitCode&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;echo&lt;/span&gt; &lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getStdOut&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;echo&lt;/span&gt; &lt;span class='nv'&gt;$cmd&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getStdErr&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Some more features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;StdIn data can be provided to the process as a parameter to &lt;code&gt;run()&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Set environment variables for the process with &lt;code&gt;setEnv()&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Second argument to &lt;code&gt;option()&lt;/code&gt; and argument to &lt;code&gt;argument()&lt;/code&gt; are automatically escaped.&lt;/li&gt;

&lt;li&gt;Options separator is white space by default, it can be changed by manually setting it as third argument to &lt;code&gt;option()&lt;/code&gt; or setting a new default with &lt;code&gt;setOptionSeparator()&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;The &lt;code&gt;proc_open&lt;/code&gt; wrapper is exposed as a static method for your convenience &lt;code&gt;Command::exec()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And finally the class which makes all that possible :)&lt;/p&gt;
&lt;script src='http://gist.github.com/420268.js?file=Command.php'&gt;.&lt;/script&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6O_UaGGyD8E:IH-5uXxVp6A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6O_UaGGyD8E:IH-5uXxVp6A:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6O_UaGGyD8E:IH-5uXxVp6A:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=6O_UaGGyD8E:IH-5uXxVp6A:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6O_UaGGyD8E:IH-5uXxVp6A:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/6O_UaGGyD8E" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/php-command-runner</feedburner:origLink></entry>
  
  <entry>
    <title>Subversion svnsync post-commit hook work around</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/jghJVPPsHfI/svnsync-postcommit" />
    <updated>2010-05-11T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/svnsync-postcommit</id>
    <content type="html">&lt;p&gt;Just a quickie for future reference. Svnsync is a tool that comes with Subversion that allows to create read-only mirrors of Subversion repositories.&lt;/p&gt;

&lt;p&gt;Creating a mirror is quite easy and usually involves the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;First we create a standard subversion repository.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; mkdir mirror
 svnadmin create mirror&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Now we have to create a pre-revprop-change hook that only allows the &lt;em&gt;svnsync&lt;/em&gt; write access to it. Remember that the mirror is read-only. Put the following contents in &lt;code&gt;mirror/hooks/pre-revprop-change&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; #!/bin/sh

 if [ &amp;quot;$3&amp;quot; = &amp;quot;svnsync&amp;quot; ]; then exit 0; fi
 echo &amp;quot;Only svnsync user may edit revision properties through svnsync&amp;quot; &amp;gt;&amp;amp;2
 exit 1&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;To activate the hook we need to give it executable permissions.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; chmod +x mirror/hooks/pre-revprop-change&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Configure the synchronization&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; svnsync init --username svnsync \
     file:///path/to/mirror \
     https://url.to/repository&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Finally perform the synchronization! You can put this command in the cron system for example to ensure the mirror is kept up-to-date.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; svnsync sync file:///path/to/mirror&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a problem though with this setup if we want to use a &lt;em&gt;post-commit hook&lt;/em&gt;. &lt;em&gt;svnsync&lt;/em&gt; works by first committing a synced revision with its own user and then, in a second step, modifies the revision properties to change the author and date to those of the original repository. This means that &lt;em&gt;post-commit&lt;/em&gt; hooks which need to obtain the revision author or date cannot be property run, since the reported author and date will be wrong.&lt;/p&gt;

&lt;p&gt;The solution is to use a different hook, &lt;em&gt;post-revprop-change&lt;/em&gt;, which is triggered each time a revision property is changed. We can have something as the following script to emulate a normal &lt;em&gt;post-commit&lt;/em&gt; hook.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;  &lt;span class='c'&gt;#!/bin/sh&lt;/span&gt;

  &lt;span class='nv'&gt;REPOS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;
  &lt;span class='nv'&gt;REV&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;$2&amp;quot;&lt;/span&gt;
  &lt;span class='nv'&gt;USER&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;$3&amp;quot;&lt;/span&gt;
  &lt;span class='nv'&gt;PROPNAME&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;$4&amp;quot;&lt;/span&gt;
  &lt;span class='nv'&gt;ACTION&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;$5&amp;quot;&lt;/span&gt;

  &lt;span class='c'&gt;# Only do actual work when the &amp;quot;svn:date&amp;quot; property is modified, which seems&lt;/span&gt;
  &lt;span class='c'&gt;# to be the last revision property modified by the svnsync process.&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;$ACTION&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;M&amp;quot;&lt;/span&gt; -a &lt;span class='s2'&gt;&amp;quot;$PROPNAME&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;svn:date&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;]&lt;/span&gt;; &lt;span class='k'&gt;then&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;&lt;span class='nv'&gt;AUTHOR&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt;svnlook author &lt;span class='nv'&gt;$REPOS&lt;/span&gt; -r &lt;span class='nv'&gt;$REV&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt;
    &lt;span class='nv'&gt;DATE&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt;svnlook date &lt;span class='nv'&gt;$REPOS&lt;/span&gt; -r &lt;span class='nv'&gt;$REV&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt;
    &lt;span class='nv'&gt;LOG&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt;svnlook log &lt;span class='nv'&gt;$REPOS&lt;/span&gt; -r &lt;span class='nv'&gt;$REV&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt;

    &lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;$REPOS@$REV: $LOG by $AUTHOR at $DATE&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;fi&lt;/span&gt;
  
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jghJVPPsHfI:aklTY9B2hSg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jghJVPPsHfI:aklTY9B2hSg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jghJVPPsHfI:aklTY9B2hSg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=jghJVPPsHfI:aklTY9B2hSg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jghJVPPsHfI:aklTY9B2hSg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/jghJVPPsHfI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/svnsync-postcommit</feedburner:origLink></entry>
  
  <entry>
    <title>New header banner</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/m7UbG3H2KpE/new-header-banner" />
    <updated>2010-03-13T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/new-header-banner</id>
    <content type="html">&lt;p&gt;&lt;em&gt;Blackies&lt;/em&gt; &lt;a href='http://es.linkedin.com/in/jljimenez'&gt;Pepe&lt;/a&gt; and &lt;a href='http://es.linkedin.com/in/juandebravo'&gt;Jdbd&lt;/a&gt; have provided this site with a much needed header banner.&lt;/p&gt;

&lt;p&gt;Kudos to them!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=m7UbG3H2KpE:-69HeaNrrl0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=m7UbG3H2KpE:-69HeaNrrl0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=m7UbG3H2KpE:-69HeaNrrl0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=m7UbG3H2KpE:-69HeaNrrl0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=m7UbG3H2KpE:-69HeaNrrl0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/m7UbG3H2KpE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/new-header-banner</feedburner:origLink></entry>
  
  <entry>
    <title>Better keyboard handling in Terminal.app</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/_dp67Sdu-8I/better-keyboard-terminal-app" />
    <updated>2010-02-28T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/better-keyboard-terminal-app</id>
    <content type="html">&lt;p&gt;Apple OSX&amp;#8217;s default terminal application, &lt;em&gt;Terminal.app&lt;/em&gt;, has matured quite a bit over the last years. It offers a good balance between compatibility with modern shells, nice font rendering and a functional user interface with support for tabs. For people comming from other operating systems however, it&amp;#8217;s a bit frustrating getting used to mac&amp;#8217;s keyboard shortcuts.&lt;/p&gt;

&lt;p&gt;The default behaviour of &lt;em&gt;home&lt;/em&gt;, &lt;em&gt;end&lt;/em&gt; and &lt;em&gt;page&lt;/em&gt; keys is specially traumatic, so after googling a fair bit&lt;sup id='fnref:1'&gt;&lt;a href='#fn:1' rel='footnote'&gt;1&lt;/a&gt;&lt;/sup&gt; I came up with the following recipies.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;th&gt;Behaviour&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;home&lt;/td&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;\033[1~&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Move to the start of the line&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;end&lt;/td&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;\033[4~&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Move to the end of the line&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;page up&lt;/td&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;\033[5~&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Search previous in the history&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;page down&lt;/td&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;\033[6~&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Search next in the history&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;option left&lt;/td&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;\033b&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Move one word left&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;option right&lt;/td&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;\033f&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Move one word right&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style='text-align: left;'&gt;forward delete&lt;/td&gt;&lt;td style='text-align: left;'&gt;&lt;code&gt;\033[3~&lt;/code&gt;&lt;/td&gt;&lt;td style='text-align: left;'&gt;Delete next char&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;To change the behaviour of a key on Terminal.app we need to access the preferences and navigate to the &lt;em&gt;keyboard&lt;/em&gt; tab. There we can modify and create new key mappings. To input &lt;code&gt;\033&lt;/code&gt; just press the Esc key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now for they to work properly we need configure &lt;em&gt;readline&lt;/em&gt; by either editing as root &lt;code&gt;/etc/inputrc&lt;/code&gt; or just creating an user file at &lt;code&gt;~/.inputrc&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Be 8bit clean
set input-meta on
set output-meta on
set convert-meta off

# allow the use of Home/End keys
&amp;quot;\e[1~&amp;quot;: beginning-of-line
&amp;quot;\e[4~&amp;quot;: end-of-line

# allow the use of Delete/Insert keys
&amp;quot;\e[3~&amp;quot;: delete-char
&amp;quot;\e[2~&amp;quot;: quoted-insert

# page up/down to search history
&amp;quot;\e[5~&amp;quot;: history-search-backward
&amp;quot;\e[6~&amp;quot;: history-search-forward&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Time to restart your terminal session and get all the previous changes to work.&lt;/p&gt;

&lt;p&gt;By the way, if you work with tabs there are two lesser known keyboard shortcuts to change between them: &lt;code&gt;Cmd+Shift+Left&lt;/code&gt; and &lt;code&gt;Cmd+Shift+Right&lt;/code&gt; will change the active tab to the left or the right.&lt;/p&gt;

&lt;p&gt;As a bonus, we can modify all &lt;em&gt;Cocoa&lt;/em&gt; based apps (Safari, Word, Mail &amp;#8230;) to behave a bit more as our newly configured terminal by creating a custom keyboard binding in &lt;code&gt;~/Library/KeyBindings/DefaultKeyBinding.dict&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    &amp;quot;\UF729&amp;quot; = &amp;quot;moveToBeginningOfLine:&amp;quot;; 
    &amp;quot;\UF72B&amp;quot; = &amp;quot;moveToEndOfLine:&amp;quot;; 
    &amp;quot;$\UF729&amp;quot; = &amp;quot;moveToBeginningOfLineAndModifySelection:&amp;quot;;
    &amp;quot;$\UF72B&amp;quot; = &amp;quot;moveToEndOfLineAndModifySelection:&amp;quot;;
    &amp;quot;\UF72C&amp;quot; = &amp;quot;pageUp:&amp;quot;; 
    &amp;quot;\UF72D&amp;quot; = &amp;quot;pageDown:&amp;quot;; 
    &amp;quot;$\UF72C&amp;quot; = &amp;quot;pageUpAndModifySelection:&amp;quot;; 
    &amp;quot;$\UF72D&amp;quot; = &amp;quot;pageDownAndModifySelection:&amp;quot;; 
}&lt;/code&gt;&lt;/pre&gt;
&lt;div class='footnotes'&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id='fn:1'&gt;
&lt;p&gt;&lt;a href='http://tech.inhelsinki.nl/gnu_developement_under_mac_os_x/'&gt;http://tech.inhelsinki.nl/gnu_developement_under_mac_os_x/&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:1' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_dp67Sdu-8I:NrkipIIFS8o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_dp67Sdu-8I:NrkipIIFS8o:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_dp67Sdu-8I:NrkipIIFS8o:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=_dp67Sdu-8I:NrkipIIFS8o:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_dp67Sdu-8I:NrkipIIFS8o:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/_dp67Sdu-8I" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/better-keyboard-terminal-app</feedburner:origLink></entry>
  
  <entry>
    <title>Consolidate e-mail accounts in GMail</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/djGgCqh1u4c/consolidate-email-accounts-gmail" />
    <updated>2010-02-25T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/consolidate-email-accounts-gmail</id>
    <content type="html">&lt;p&gt;Over time GMail has been giving options to easily consolidate email accounts with them, however they offer it under its conditions, which might not always match your requirements.&lt;/p&gt;

&lt;p&gt;For example, they allow to fetch mail from a remote account with POP3 only, not IMAP. Moreover, the frequency by which they fetch new mails is not very reliable, going from 5 minutes to upto an hour!&lt;/p&gt;

&lt;p&gt;Recently they introduced the posibility to use a remote SMTP server to deliver emails from consolidated email addresses, &lt;em&gt;fixing&lt;/em&gt; the issue with Outlook mail clients displaying the infamous &lt;em&gt;&amp;#8220;on behalf of&amp;#8221;&lt;/em&gt; tag. However they only support remote SMTP servers offering secured connections (TLS) or at least secured logins (STARTTLS).&lt;/p&gt;

&lt;p&gt;To solve the mail forwarding issue, a veteran program by the name of &lt;a href='http://fetchmail.berlios.de'&gt;fetchmail&lt;/a&gt; can be easily used. Here is my config to fetch email via the IMAP protocol and forward it using a &lt;em&gt;sendmail&lt;/em&gt; like command line &lt;em&gt;MDA&lt;/em&gt; tool.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;/etc/fetchmailrc&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set daemon 120

poll MY.IMAP.SERVER imap
    username &amp;quot;MY_REMOTE_USERNAME&amp;quot; password &amp;quot;MY_REMOTE_PASSWORD&amp;quot;
    smtpname &amp;quot;MY_GMAIL_USERNAME+MY_TAG@gmail.com&amp;quot;
    keep
    mda &amp;#39;/usr/sbin/sendmail MY_GMAIL_USERNAME@gmail.com&amp;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fetchmail will even allow to specify which IMAP folders to fetch, so you can configure it to also forward your &lt;em&gt;Sent&lt;/em&gt; folder for example.&lt;/p&gt;

&lt;p&gt;Since I didn&amp;#8217;t want to install a full SMTP server just for forwarding the email, I went with &lt;a href='http://msmtp.sourceforge.net'&gt;msmtp&lt;/a&gt;, which is a SMTP client for relaying to a SMTP mailhub or &lt;em&gt;smart host&lt;/em&gt;. Note that we can&amp;#8217;t use GMail&amp;#8217;s SMTP server for this task, since it&amp;#8217;ll rewrite the &lt;em&gt;From&lt;/em&gt; header from the messages, meaning that all the emails will look like they come from ourselves.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;/etc/msmtprc&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defaults
tls off
logfile /var/log/msmtp.log

account MY_ACCOUNT
host SMTP.HOST.NET
port 25
auth login
user SMTP_USERNAME
password SMTP_PASSWORD
from SMTP_EMAIL_ADDRESS

account default : MY_ACCOUNT&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;msmtp&lt;/em&gt; should install a &lt;em&gt;symlink&lt;/em&gt; under &lt;code&gt;/usr/sbin/sendmail&lt;/code&gt; so it gets somewhat compatible with it for the most simple tasks. Note that it won&amp;#8217;t do local delivery but instead connect to the configured SMTP server to relay the email messages.&lt;/p&gt;

&lt;p&gt;With this setup I can get new messages almost instantly in GMail. Now I needed to solve the use of a custom SMTP server in GMail, to avoid the &lt;em&gt;&amp;#8220;on behalf of&amp;#8221;&lt;/em&gt; issue with Outlook recipients.&lt;/p&gt;

&lt;p&gt;Since the SMTP server of my consolidated account didn&amp;#8217;t offer TLS neither STARTTLS, I had to create a secure tunnel for it in my hosting server with &lt;a href='http://stunnel.org'&gt;stunnel&lt;/a&gt;. You can learn to generate a certificate for the SSL connections from its site and documentation. What follows is just the section of the configuration to secure the SMTP tunnel.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[ssmtp]
accept = 587
connect = REMOTE.SMTP.SERVER:25
protocol = smtp&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now in GMail settings I can simply configure a remote SMTP server for my consolidated email by using the address of the server running the tunnel on port 587, which upon a connection will &lt;em&gt;proxy&lt;/em&gt; the request to the actual remote SMTP server.&lt;/p&gt;

&lt;p&gt;Finally I have a really consolidated external email address in GMail. The setup is quite easy to implement and light on resources.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=djGgCqh1u4c:7UXW1Zr-WC0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=djGgCqh1u4c:7UXW1Zr-WC0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=djGgCqh1u4c:7UXW1Zr-WC0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=djGgCqh1u4c:7UXW1Zr-WC0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=djGgCqh1u4c:7UXW1Zr-WC0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/djGgCqh1u4c" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/consolidate-email-accounts-gmail</feedburner:origLink></entry>
  
  <entry>
    <title>Migrating the blog to Jekyll</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/kdDSJJnyrWM/migrating-the-blog-to-jekyll" />
    <updated>2010-01-30T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/migrating-the-blog-to-jekyll</id>
    <content type="html">&lt;p&gt;Since I barely post anything new in this blog any more I thought that migrate it to a new system might bring some more life to it. It started years ago running on &lt;a href='http://textpattern.com'&gt;Textpattern&lt;/a&gt;, then I migrated to &lt;a href='http://drupal.org'&gt;Drupal&lt;/a&gt; since I wanted to experiment with it a bit and now it&amp;#8217;s being generated with &lt;a href='http://github.com/mojombo/jekyll'&gt;Jekyll&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The former two use a database for persistence of the content while the later, Jekyll, generates static files from the content which are then uploaded to the web server hosting this blog. The change has been quite nice, since now I don&amp;#8217;t need to login into a CMS administration web panel and get lost in the little details of each publishing system. My workflow is improved because I&amp;#8217;m &lt;em&gt;forced&lt;/em&gt; now to write the content using my preferred text editor, even when I&amp;#8217;m offline, allowing me to concentrate on the content instead of the &lt;em&gt;tool&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Even if publishing gets a bit more complicated, involving &lt;em&gt;rsync&lt;/em&gt;&amp;#8216;ing the new content on my laptop with the published html files in the server, there is a great advantage in having a system which generates a static rendition of the site. Since no database or interpreted language is needed, the runtime can be served with a very simple and efficient setup. It&amp;#8217;s allowed me to bring down the server steady memory usage from 120Mb of my previous &lt;em&gt;&lt;abbr title='Linux Apache MySQL and PHP'&gt;LAMP&lt;/abbr&gt;&lt;/em&gt; setup to a mere 30Mb of the current &lt;a href='http://nginx.net'&gt;nginx&lt;/a&gt; one.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=kdDSJJnyrWM:ijkExsoVLJc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=kdDSJJnyrWM:ijkExsoVLJc:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=kdDSJJnyrWM:ijkExsoVLJc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=kdDSJJnyrWM:ijkExsoVLJc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=kdDSJJnyrWM:ijkExsoVLJc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/kdDSJJnyrWM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/migrating-the-blog-to-jekyll</feedburner:origLink></entry>
  
  <entry>
    <title>Netbeans and Ubuntu 64bits</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/ylbmte9xNDU/netbeans-ubuntu-64" />
    <updated>2009-11-23T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/netbeans-ubuntu-64</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve been having some very annoying problems with Netbeans IDE running under Ubuntu Jaunty and Karmic. The Java virtual machine process would start to consume memory, probably due to a bug in Netbeans, at a very fast rate, after just 20 minutes of moderate use it would have consumed about 1Gb of RAM. This means that, on my 2GB laptop, the system starts to paginate the memory on disk, severely affecting the overall performance of the system.&lt;/p&gt;

&lt;p&gt;It was a strange behavior since one of the reasons why I settled on Netbeans recently is that it was more responsive and less demanding on resources than Eclipse. I certainly didn&amp;#8217;t have any problem with it on Windows (Xp and Vista) or Apple&amp;#8217;s OSX.&lt;/p&gt;

&lt;p&gt;The culprit seems to be the JDK used. I installed the Sun version of the JDK via the official apt repositories, since my system is 64bits it installed the 64bits version of the JDK. Unfortunately there is something wrong with it, at least when used for Netbeans, since changing to the 32bit version of the JDK seems to have solved the problem. At least the memory consumption stays below the 300Mb after a couple of hours.&lt;/p&gt;

&lt;p&gt;These are the steps I took to install the 32bit JDK on Ubuntu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Obtain java-package: sudo apt-get install java-package&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;a href='http://java.sun.com/javase/downloads/widget/jdk6.jsp'&gt;Download the 32bit binary, just the JDK, from Sun&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Create a deb package from the JDK binary we just downloaded:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; DEB_BUILD_GNU_TYPE=i486-linux-gnu DEB_BUILD_ARCH=i386 fakeroot make-jpkg jdk.xxx.bin&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Install the created deb package&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; sudo dpkg -i sun-xxx.deb&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Now edit your &lt;a href='http://wiki.netbeans.org/FaqNetbeansConf'&gt;netbeans.conf&lt;/a&gt; file and point &lt;code&gt;netbeans_jdkhome&lt;/code&gt; to the newly installed JDK directory. You can know it by checking the installed Java environments with &lt;code&gt;sudo update-alternatives -config java&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ylbmte9xNDU:mc_lVo76PAI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ylbmte9xNDU:mc_lVo76PAI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ylbmte9xNDU:mc_lVo76PAI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=ylbmte9xNDU:mc_lVo76PAI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ylbmte9xNDU:mc_lVo76PAI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/ylbmte9xNDU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/netbeans-ubuntu-64</feedburner:origLink></entry>
  
  <entry>
    <title>Optimizing Javascript and CSS downloads with Zend Framework</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/P7vMNNIFbhc/optimizing-js-css-zend-framework" />
    <updated>2009-08-27T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/optimizing-js-css-zend-framework</id>
    <content type="html">&lt;p&gt;Modern web sites and applications require the use of many javascript and css files. If not done with care this can affect the user&amp;#8217;s experience. One of the easiest methods to improve the performance is by concatenating and minimizing the individual files into &lt;em&gt;bundles&lt;/em&gt;, reducing this way the number of downloads and the total size to be downloaded.&lt;/p&gt;

&lt;p&gt;One problem with this approach though is that during development phases it&amp;#8217;s important to work with the original source files, so it&amp;#8217;s easier to debug or perform changes in them. From the developer&amp;#8217;s point of view it&amp;#8217;s ideal to work with small files.&lt;/p&gt;

&lt;p&gt;Zend Framework offers an interesting way to include external javascript and css files in your pages. The &lt;code&gt;headLink&lt;/code&gt; and &lt;code&gt;headScript&lt;/code&gt; view helpers allow to include files in the page at any point in the execution which will be finally added to the head section of your layout just before sending the page to the browser. Since all the files are actually added to page at the end of the request we can override those helpers and filter their contents to replace the individual files with our bundles.&lt;/p&gt;

&lt;p&gt;Fortunately, both helpers implement the Iterator interface, which means that&amp;#8217;s very easy to attach a filter mechanism to them. First thing we need is a filtering iterator as shown here:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='sd'&gt;/** vim: ff=unix fenc=utf8 tw=80 ts=4 sw=4 et ai&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * Implements a filter iterator designed to modify the default behaviour of Zend&lt;/span&gt;
&lt;span class='sd'&gt; * view helpers HeadLink and HeadScript to support the runtime replacement&lt;/span&gt;
&lt;span class='sd'&gt; * of individual javascript and css files for its corresponding bundles.&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * License&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * Permission is hereby granted, free of charge, to any person obtaining a copy&lt;/span&gt;
&lt;span class='sd'&gt; * of this software and associated documentation files (the &amp;quot;Software&amp;quot;), to deal&lt;/span&gt;
&lt;span class='sd'&gt; * in the Software without restriction, including without limitation the rights&lt;/span&gt;
&lt;span class='sd'&gt; * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&lt;/span&gt;
&lt;span class='sd'&gt; * copies of the Software, and to permit persons to whom the Software is&lt;/span&gt;
&lt;span class='sd'&gt; * furnished to do so, subject to the following conditions:&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * The above copyright notice and this permission notice shall be included in&lt;/span&gt;
&lt;span class='sd'&gt; * all copies or substantial portions of the Software.&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&lt;/span&gt;
&lt;span class='sd'&gt; * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&lt;/span&gt;
&lt;span class='sd'&gt; * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&lt;/span&gt;
&lt;span class='sd'&gt; * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&lt;/span&gt;
&lt;span class='sd'&gt; * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&lt;/span&gt;
&lt;span class='sd'&gt; * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&lt;/span&gt;
&lt;span class='sd'&gt; * THE SOFTWARE.&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * @copyright   Copyright (c) 2009 Iván Montes&lt;/span&gt;
&lt;span class='sd'&gt; * @author      Iván -DrSlump- Montes &amp;lt;drslump@pollinimini.net&amp;gt;&lt;/span&gt;
&lt;span class='sd'&gt; */&lt;/span&gt;
&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;BundlesFilterIterator&lt;/span&gt; &lt;span class='k'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;FilterIterator&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='sd'&gt;/** @var array */&lt;/span&gt;
    &lt;span class='k'&gt;protected&lt;/span&gt; &lt;span class='nv'&gt;$_files&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
    &lt;span class='sd'&gt;/** @var array */&lt;/span&gt;
    &lt;span class='k'&gt;protected&lt;/span&gt; &lt;span class='nv'&gt;$_included&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Constructor&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param Iterator $iterator&lt;/span&gt;
&lt;span class='sd'&gt;     * @param array $bundles&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;__construct&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$iterator&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$bundles&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='c1'&gt;// Reverses the array placing the individual files as keys and the&lt;/span&gt;
        &lt;span class='c1'&gt;// bundle files as values&lt;/span&gt;
        &lt;span class='k'&gt;foreach&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$bundles&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='nv'&gt;$bundle&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='nv'&gt;$files&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='k'&gt;foreach&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$files&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='nv'&gt;$file&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_files&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$file&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$bundle&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;parent&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;__construct&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$iterator&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Performs the filtering&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @return bool&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;accept&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='c1'&gt;// Get the current item&lt;/span&gt;
        &lt;span class='nv'&gt;$item&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getInnerIterator&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;current&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;

        &lt;span class='c1'&gt;// Check if it is an external javascript or css file&lt;/span&gt;
        &lt;span class='nv'&gt;$type&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;js&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='nv'&gt;$src&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;isset&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;src&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;src&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$src&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nv'&gt;$type&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;css&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
            &lt;span class='nv'&gt;$src&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;isset&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;href&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;href&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$src&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class='c1'&gt;// The individual file is in a bundle&lt;/span&gt;
            &lt;span class='nb'&gt;isset&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_files&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$src&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class='c1'&gt;// Check if it is a normal include&lt;/span&gt;
            &lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;defer&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;conditional&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;conditionalStylesheet&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

            &lt;span class='c1'&gt;// Get the bundle file&lt;/span&gt;
            &lt;span class='nv'&gt;$bundle&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_files&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$src&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;

            &lt;span class='c1'&gt;// If its bundle was not yet included do so now&lt;/span&gt;
            &lt;span class='c1'&gt;// The HeadXXXX helpers will also check for this but still...&lt;/span&gt;
            &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_included&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$bundle&lt;/span&gt;&lt;span class='p'&gt;]))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_included&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$bundle&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
                &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$type&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;js&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                        &lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;src&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$bundle&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
                &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                        &lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;href&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$bundle&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
                &lt;span class='p'&gt;}&lt;/span&gt;
                &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;

            &lt;span class='c1'&gt;// Otherwise we do nothing with this item&lt;/span&gt;
            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we need to override the view helpers to add the filtering iterator&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;DrSlump_View_Helper_HeadLink&lt;/span&gt; &lt;span class='k'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Zend_View_Helper_HeadLink&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Override the default iterator with a filtering one&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @return BundlesFilterIterator&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;getIterator&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nv'&gt;$iterator&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getContainer&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getIterator&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
        &lt;span class='nv'&gt;$bundles&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Zend_Registry&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;bundles&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$bundles&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='nv'&gt;$iterator&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;BundlesFilterIterator&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$iterator&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$bundles&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;DrSlump_View_Helper_HeadScript&lt;/span&gt; &lt;span class='k'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Zend_View_Helper_HeadScript&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;         * Override the default iterator with a filtering one&lt;/span&gt;
&lt;span class='sd'&gt;         *&lt;/span&gt;
&lt;span class='sd'&gt;         * @return BundlesFilterIterator&lt;/span&gt;
&lt;span class='sd'&gt;         */&lt;/span&gt;
        &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;getIterator&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
        &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$iterator&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getContainer&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getIterator&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
                &lt;span class='nv'&gt;$bundles&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Zend_Registry&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;bundles&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
 
                &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$bundles&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='nv'&gt;$iterator&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;BundlesFilterIterator&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$iterator&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$bundles&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we just need to map our small individual files with the bundle files in which they are contained:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='nv'&gt;$bundles&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
    &lt;span class='c1'&gt;// For jQuery we use a public CDN&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;/js/jquery-1.3.2.js&amp;#39;&lt;/span&gt;
    &lt;span class='p'&gt;),&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;/resources/bundle-plugins.js&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;/js/jquery/jquery.event.drag.js&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;/js/jquery/password_strength_plugin.js&amp;#39;&lt;/span&gt;
    &lt;span class='p'&gt;),&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;/resources/bundle.css&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;/css/reset.css&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;/css/global.css&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;/css/forms.css&amp;#39;&lt;/span&gt;
    &lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Store the bundles configuration in the registry so that it can be fetched by the view helpers&lt;/span&gt;
&lt;span class='nx'&gt;Zend_Registry&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;set&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;bundles&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$bundles&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When defining the bundles mapping we&amp;#8217;re assigning the bundle URL as key to an array of the individual files URLs we&amp;#8217;re using in the code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This code does &lt;strong&gt;NOT&lt;/strong&gt; create the bundles. There are several tools available for that task. The purpose of the examples above is to show how to use those bundles in an application without having to think about them when coding or even apply them to an existing application without having to modify the source code.&lt;/p&gt;
&lt;/blockquote&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P7vMNNIFbhc:DUJXKgC-2T0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P7vMNNIFbhc:DUJXKgC-2T0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P7vMNNIFbhc:DUJXKgC-2T0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=P7vMNNIFbhc:DUJXKgC-2T0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P7vMNNIFbhc:DUJXKgC-2T0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/P7vMNNIFbhc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/optimizing-js-css-zend-framework</feedburner:origLink></entry>
  
  <entry>
    <title>Runtime, annotations based, lexer generator</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/Ozmu5TAIgrw/runtime-annotations-based-lexer-generator" />
    <updated>2009-08-14T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/runtime-annotations-based-lexer-generator</id>
    <content type="html">&lt;p&gt;Just a quick post to publish this class. It allows to easily create lexers (or lexical scanners or tokenizers) by either extending the class or pointing it to a class or object.&lt;/p&gt;

&lt;p&gt;Takes advantage of PHP&amp;#8217;s Reflection API to explore the document blocks of your class looking for special annotations describing patterns (regular expressions) and rules.&lt;/p&gt;

&lt;p&gt;Some features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;First to match&amp;#8221; and &amp;#8220;longest match&amp;#8221; lexing modes.&lt;/li&gt;

&lt;li&gt;States based lexer with support for a states stack&lt;/li&gt;

&lt;li&gt;Rules can consume, ignore, repeat in a different state or repeat skipping the rule just matched&lt;/li&gt;

&lt;li&gt;Implements the iterator interface so it can be used in foreach() loops for example&lt;/li&gt;

&lt;li&gt;Reports lexing failures indicating the position in the text plus the line and column&lt;/li&gt;

&lt;li&gt;Caches the internal lexer information so the annotations are only parsed once&lt;/li&gt;

&lt;li&gt;Allows to save and restore the internal lexer information so it can persisted and cached between requests&lt;/li&gt;
&lt;/ul&gt;
&lt;script src='http://gist.github.com/167494.js?file=AnnotationsLexerGenerator.php'&gt;
&lt;/script&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ozmu5TAIgrw:r0M3ej9fNSM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ozmu5TAIgrw:r0M3ej9fNSM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ozmu5TAIgrw:r0M3ej9fNSM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=Ozmu5TAIgrw:r0M3ej9fNSM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ozmu5TAIgrw:r0M3ej9fNSM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/Ozmu5TAIgrw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/runtime-annotations-based-lexer-generator</feedburner:origLink></entry>
  
  <entry>
    <title>Finally HTML5 goodness for the real world</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/QNDE39hxi8w/html5-goodness-real-world" />
    <updated>2009-04-10T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/html5-goodness-real-world</id>
    <content type="html">&lt;p&gt;Firefox 3.1b3 has arrived and it&amp;#8217;s stuffed with a ton of new web technologies. Most of the stuff comes from the &lt;a href='http://www.whatwg.org/'&gt;WhatWG&lt;/a&gt; working drafts, which should mean that major browser vendors (Mozilla, Microsoft, Opera, Apple and Google) are aware of the specifications and will incorporate them at some point.&lt;/p&gt;

&lt;p&gt;I love this release of Firefox because it is really a giant step forward for web developers, stuff like &lt;a href='http://www.whatwg.org/specs/web-workers/current-work'&gt;web workers&lt;/a&gt; (a simple threading scheme for web applications), cross site XMLHttpRequest via &lt;a href='http://dev.w3.org/2006/waf/access-control'&gt;access control in the server&lt;/a&gt;, native JSON support (really fast!), &lt;a href='http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#dnd'&gt;Drag-n-Drop events&lt;/a&gt; and &lt;a href='http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html'&gt;Offline persistance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Together with the inclusion by default of the &lt;a href='https://wiki.mozilla.org/JavaScript:TraceMonkey'&gt;TraceMonkey javascript engine&lt;/a&gt;, these features put Firefox again as the ultimate web development platform.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=QNDE39hxi8w:twVklE9gyEU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=QNDE39hxi8w:twVklE9gyEU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=QNDE39hxi8w:twVklE9gyEU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=QNDE39hxi8w:twVklE9gyEU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=QNDE39hxi8w:twVklE9gyEU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/QNDE39hxi8w" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/html5-goodness-real-world</feedburner:origLink></entry>
  
  <entry>
    <title>My new programming font: Inconsolata</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/UkHxNRQ3q_4/my-new-programming-font-inconsolata" />
    <updated>2009-03-16T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/my-new-programming-font-inconsolata</id>
    <content type="html">&lt;p&gt;Just a short post to announce a jewel I&amp;#8217;ve just found. The &lt;a href='http://www.levien.com/type/myfonts/inconsolata.html'&gt;Inconsolata font&lt;/a&gt; is a great monospace font suitable to use in text terminals and code editors or IDEs.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s replacing now the ancient Mac&amp;#8217;s Monaco which has served damn well over the years but I feel like I needed a change and Inconsolata feels bolder and more vibrant than Monaco or Microsoft&amp;#8217;s Consolas.&lt;/p&gt;

&lt;p&gt;Update: This font was initially conceived for printing so it doesn&amp;#8217;t perform well at small sizes, so to get it at its full glory I recommed a size of at least 12 points over a dark background.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=UkHxNRQ3q_4:XHOC9FH1AqY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=UkHxNRQ3q_4:XHOC9FH1AqY:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=UkHxNRQ3q_4:XHOC9FH1AqY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=UkHxNRQ3q_4:XHOC9FH1AqY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=UkHxNRQ3q_4:XHOC9FH1AqY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/UkHxNRQ3q_4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/my-new-programming-font-inconsolata</feedburner:origLink></entry>
  
  <entry>
    <title>A solution to PHP's new namespace separator moaning</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/C7CTY18mXDw/solution-php-namespace-separator-moaning" />
    <updated>2008-11-09T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/solution-php-namespace-separator-moaning</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve been quite busy lately but I&amp;#8217;ve obviously been exposed to all the fud about the PHP internals decission of choosing the back-slash as the namespace separator.&lt;/p&gt;

&lt;p&gt;So to keep everyone happy I&amp;#8217;ve spent a few minutes working on a solution to the problem and here it goes:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;NsFixerFileStream&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;protected&lt;/span&gt; &lt;span class='nv'&gt;$fp&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;protected&lt;/span&gt; &lt;span class='nv'&gt;$separator&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;:::&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;protected&lt;/span&gt; &lt;span class='nv'&gt;$isPHP&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='nv'&gt;$context&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;stream_open&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$mode&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='nv'&gt;$opened_path&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;context&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;context&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;stream_context_get_default&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='nv'&gt;$opts&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;stream_context_get_options&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;context&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$opts&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$opts&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;separator&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;separator&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$opts&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;separator&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;isPHP&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;pathinfo&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;PATHINFO_EXTENSION&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;php&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

        &lt;span class='nb'&gt;stream_wrapper_restore&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;fopen&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$mode&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='nb'&gt;stream_wrapper_unregister&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='nb'&gt;stream_wrapper_register&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;get_class&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='p'&gt;));&lt;/span&gt;

        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;stream_read&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$count&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nv'&gt;$data&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;fread&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$count&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;isPHP&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$data&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;str_replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;separator&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;\\&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;stream_write&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;fwrite&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;stream_tell&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;ftell&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;stream_eof&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;feof&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;stream_seek&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$offset&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$whence&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;fseek&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$offset&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$whence&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;stream_stat&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;fstat&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fp&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;


&lt;span class='c1'&gt;// Replace default stream wrapper with out custom one&lt;/span&gt;
&lt;span class='nb'&gt;stream_wrapper_unregister&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nb'&gt;stream_wrapper_register&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;NsFixerFileStream&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;or&lt;/span&gt; &lt;span class='k'&gt;die&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Failed to register protocol&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Define the default namespace separator&lt;/span&gt;
&lt;span class='nx'&gt;stream_context_set_default&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;file&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
                &lt;span class='s1'&gt;&amp;#39;separator&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;:::&amp;#39;&lt;/span&gt;
        &lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;));&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For the least versed on PHP&amp;#8217;s stream wrappers, what it does is replace the standard file i/o stream with one that replaces on the fly everything you like to be a namespace separator with an ugly back-slash. Just place this on a file on your server and add its location to your &lt;code&gt;auto_prepend_file&lt;/code&gt; ini directive.&lt;/p&gt;

&lt;p&gt;Now you can spend your time writing stuff like the following instead of blogging about how the ugly back-slash in your code can ruin your way of life :)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='nx'&gt;namespace&lt;/span&gt; &lt;span class='nx'&gt;DRSLUMP&lt;/span&gt;&lt;span class='o'&gt;:::&lt;/span&gt;&lt;span class='nx'&gt;test&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;foo&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;static&lt;/span&gt; &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;bar&lt;/span&gt;&lt;span class='p'&gt;(){&lt;/span&gt;
        &lt;span class='o'&gt;:::&lt;/span&gt;&lt;span class='nb'&gt;printf&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Hello %s!&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;world&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='o'&gt;:::&lt;/span&gt;&lt;span class='nx'&gt;DRSLUMP&lt;/span&gt;&lt;span class='o'&gt;:::&lt;/span&gt;&lt;span class='nx'&gt;test&lt;/span&gt;&lt;span class='o'&gt;:::&lt;/span&gt;&lt;span class='nx'&gt;foo&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;bar&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=C7CTY18mXDw:FtkqdCFfYC0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=C7CTY18mXDw:FtkqdCFfYC0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=C7CTY18mXDw:FtkqdCFfYC0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=C7CTY18mXDw:FtkqdCFfYC0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=C7CTY18mXDw:FtkqdCFfYC0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/C7CTY18mXDw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/solution-php-namespace-separator-moaning</feedburner:origLink></entry>
  
  <entry>
    <title>Tags emulation for Zend_Cache</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/XztUn0fUTcI/tags-emulation-zend-cache" />
    <updated>2008-08-06T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/tags-emulation-zend-cache</id>
    <content type="html">&lt;p&gt;Managing a cache is a complex task, at first you start placing random stuff on it, when you need to squeeze a few more hits per second you keep adding stuff to the cache. At the end of the day, if you&amp;#8217;ve not planned it carefully, you might end up with a nightmare of stale data in your pages or even a completely broken site.&lt;/p&gt;

&lt;p&gt;One easy way to apply some logic to the cached data and help in the invalidation of cached stuff is the use of tags. Cache tags are a simple way to group cached items so it gets easy to remove/invalidate them if needed. For example, if we have an online shop and we are caching paginated list of items by their category, then we might have keys like &lt;code&gt;list-{category}-{startOffset}&lt;/code&gt;, if we add a new item to our shop we have to invalidate all the cached partial lists (since it could be at any position in the list). If we apply a simple tag, like &lt;code&gt;list-{category}&lt;/code&gt; to the cached lists we can group them and proceed to their invalidation when a new product is added or moved to a given category, so our online data is always fresh.&lt;/p&gt;

&lt;p&gt;The &lt;a href='http://framework.zend.com/'&gt;Zend Framework&lt;/a&gt; implements tag support in its cache component, but unfortunately not APC neither the high performance Memcached do support grouping or tags. For the later one there is a fork/patch, &lt;a href='http://code.google.com/p/memcached-tag'&gt;memcached-tag&lt;/a&gt;, however it does not seem to be very mature yet as to use in production.&lt;/p&gt;

&lt;p&gt;Still not everything is lost, we can emulate tag support by keeping ourselves a relation between cache keys and tags. The first thing that comes to mind is to self-store this relation in the cache, however APC and Memcached may drop a cache item without further notice, they are caches not persistency layers, so we need to find a persistent store to keep this information. The solution below uses a PDO connection (MySQL, Sqlite, Oracle…) to keep the relation between keys and tags in a table, this table is updated each time there is a cache write (with tags) and when cleaning by tag, so it shouldn&amp;#8217;t hurt much performance if your cache hit is high (the overhead won&amp;#8217;t matter much anyway if you get a lot of misses).&lt;/p&gt;

&lt;p&gt;By the way, the code is licensed under the BSD License, so feel free to use it at will as long as you keep the copyright notice in place.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://svn.pollinimini.net/public/Zend_Cache_Backend_Tags.php'&gt;Download it from my public subversion repository.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we only have a single server we can use a simple Sqlite database. For distributed memcached servers we&amp;#8217;ll need a server based database system like MySql (Note: To improve performance in MySQL it&amp;#8217;s desirable to use the Memory table engine if we don&amp;#8217;t need the cache to survive our MySQL instance).&lt;/p&gt;

&lt;p&gt;Following is a simple usage example for the class (Remember to rename the file to the usual ZF directory structure &lt;code&gt;Zend/Cache/Backend/Tags.php&lt;/code&gt;).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='c1'&gt;// Setup the cache&lt;/span&gt;
&lt;span class='nv'&gt;$frontOpts&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
   &lt;span class='s1'&gt;&amp;#39;lifetime&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='m'&gt;3600&lt;/span&gt;
&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nv'&gt;$backOpts&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
  &lt;span class='c1'&gt;// Setup the real cache backend&lt;/span&gt;
  &lt;span class='s1'&gt;&amp;#39;backend&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;class&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Zend_Cache_Backend_Apc&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;options&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
    &lt;span class='p'&gt;),&lt;/span&gt;
  &lt;span class='p'&gt;),&lt;/span&gt;
  &lt;span class='c1'&gt;// Configure the persistent store for the keys-tags mapping&lt;/span&gt;
  &lt;span class='s1'&gt;&amp;#39;pdo&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;dsn&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;mysql:host=127.0.0.1;dbname=cachedb&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;user&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;dbuser&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;password&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;dbpass&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='p'&gt;),&lt;/span&gt;
  &lt;span class='c1'&gt;// Set to true if you want to delete non tagged keys&lt;/span&gt;
  &lt;span class='s1'&gt;&amp;#39;track_untagged&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
  &lt;span class='c1'&gt;// Set this to true if you don&amp;#39;t want to have duplicates in the table,&lt;/span&gt;
  &lt;span class='c1'&gt;// it could improve performace a bit&lt;/span&gt;
  &lt;span class='s1'&gt;&amp;#39;duplicates_ok&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;
&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Create the cache object&lt;/span&gt;
&lt;span class='nv'&gt;$cache&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;factory&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;core&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;tags&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$frontOps&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$backOps&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Store some stuff in the cache&lt;/span&gt;
&lt;span class='nv'&gt;$cache&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;save&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;My cached data #1&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;cacheA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tagA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nv'&gt;$cache&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;save&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;My cached data #2&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;cacheB&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tagA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nv'&gt;$cache&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;save&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;My cached data #3&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;cacheC&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tagB&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Clean all the keys with tagA&lt;/span&gt;
&lt;span class='nv'&gt;$cache&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;clean&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;CLEANING_MODE_MATCHING_TAG&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tagA&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='update_20090307'&gt;Update 2009-03-07&lt;/h2&gt;

&lt;p&gt;Jan ‘Mithrandir’ Pedersen has provided in the comments a modification of the class based on Zend_Db_Table instead of PDO. Here is the code:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt; * Zend_Cache Tags emulator for backends not supporting them natively&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * It&amp;#39;ll use a Zend_Db_Table_Abstract object to persist the mapping&lt;/span&gt;
&lt;span class='sd'&gt; * between cache keys and its tags.&lt;/span&gt;
&lt;span class='sd'&gt; *&lt;/span&gt;
&lt;span class='sd'&gt; * @author ZooCMS Crew&lt;/span&gt;
&lt;span class='sd'&gt; * @credits Iván -DrSlump- Montes &amp;lt;drslump AT pollinimini DOT net&amp;gt;&lt;/span&gt;
&lt;span class='sd'&gt; * @copyright Copyright (c) 2009 ZooCMS Crew&lt;/span&gt;
&lt;span class='sd'&gt; * @copyright Copyright (c) 2008 Iván -DrSlump- Montes &amp;lt;http://pollinimini.net&amp;gt;&lt;/span&gt;
&lt;span class='sd'&gt; * @version 1.0&lt;/span&gt;
&lt;span class='sd'&gt; * @license BSD&lt;/span&gt;
&lt;span class='sd'&gt; */&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Zoo_Cache_Backend_Tags&lt;/span&gt; &lt;span class='k'&gt;extends&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache_Backend&lt;/span&gt; &lt;span class='k'&gt;implements&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache_Backend_Interface&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Available options&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * =====&amp;gt; (Zend_Cache_Core) backend:&lt;/span&gt;
&lt;span class='sd'&gt;     * A Zend_Cache_Backend object or an associative array declaring its configuration:&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;class&amp;#39; =&amp;gt; (string) The full class name of the backend&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;options&amp;#39; =&amp;gt; (array) The array of options passed to the class constructor&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * =====&amp;gt; (array) table:&lt;/span&gt;
&lt;span class='sd'&gt;     * An associative array with the Zend_Db_Table_Abstract class data:&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;class&amp;#39; =&amp;gt; string) The full class name of the backend&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;options&amp;#39; =&amp;gt; (array) additional configuration parameters to use with Zend_Db_Table_Abstract::__construct()&lt;/span&gt;
&lt;span class='sd'&gt;     * It is assumed that the table will have an &amp;#39;cacheid&amp;#39; and a &amp;#39;tag&amp;#39; column&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * =====&amp;gt; (book) track_untagged:&lt;/span&gt;
&lt;span class='sd'&gt;     * If true it will keep track of untagged items so they can be purged by the NOT_MATCHING_TAG mode&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * =====&amp;gt; (book) duplicates_ok:&lt;/span&gt;
&lt;span class='sd'&gt;     * If true it won&amp;#39;t make sure that there are no duplicate entries in the database.&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @var array available options&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;protected&lt;/span&gt; &lt;span class='nv'&gt;$_options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;backend&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;table&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;track_untagged&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;duplicates_ok&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;
    &lt;span class='p'&gt;);&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Zend_Cache_Core object&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @var Zend_Cache_Core object&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;private&lt;/span&gt; &lt;span class='nv'&gt;$_backend&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Table object&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @var Zend_Db_Table_Abstract object&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;private&lt;/span&gt; &lt;span class='nv'&gt;$_table&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Constructor&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param array $options associative array of options&lt;/span&gt;
&lt;span class='sd'&gt;     * @throws Zend_Cache_Exception&lt;/span&gt;
&lt;span class='sd'&gt;     * @return void&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;__construct&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;())&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;parent&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;__construct&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nb'&gt;is_array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;backend&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

            &lt;span class='nv'&gt;$backendClass&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;backend&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;

            &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nv'&gt;$backendClass&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;backend&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;options&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;

        &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;backend&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='nx'&gt;instanceof&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache_Backend_Interface&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

            &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;backend&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;

        &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;throwException&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;The backend option is not correctly set!&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nb'&gt;is_array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;table&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;throwException&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;The table option is not correctly set!&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Test if a cache is available for the given id and (if yes) return it (false else)&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param string $id Cache id&lt;/span&gt;
&lt;span class='sd'&gt;     * @param boolean $doNotTestCacheValidity If set to true, the cache validity won&amp;#39;t be tested&lt;/span&gt;
&lt;span class='sd'&gt;     * @return string|false cached datas&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;load&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$doNotTestCacheValidity&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nv'&gt;$result&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;load&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$doNotTestCacheValidity&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='c1'&gt;// If not in cache make sure to delete the tag mapping to handle cache expiration&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$result&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;duplicates_ok&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nv'&gt;$where&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getAdapter&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;quoteInto&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;cacheid = ?&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;delete&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$where&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$result&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Get Zend_Db_Table_Abstract object for persistence&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;protected&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_table&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nv'&gt;$tableClass&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;table&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
            &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_table&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nv'&gt;$tableClass&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;table&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;][&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;options&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_table&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Test if a cache is available or not (for the given id)&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param string $id Cache id&lt;/span&gt;
&lt;span class='sd'&gt;     * @return mixed|false (a cache is not available) or &amp;quot;last modified&amp;quot; timestamp (int) of the available cache record&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;test&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;test&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Save some string datas into a cache record&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * Note : $data is always &amp;quot;string&amp;quot; (serialization is done by the&lt;/span&gt;
&lt;span class='sd'&gt;     * core not by the backend)&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param string $data Datas to cache&lt;/span&gt;
&lt;span class='sd'&gt;     * @param string $id Cache id&lt;/span&gt;
&lt;span class='sd'&gt;     * @param array $tags Array of strings, the cache record will be tagged by each string entry&lt;/span&gt;
&lt;span class='sd'&gt;     * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null =&amp;gt; infinite lifetime)&lt;/span&gt;
&lt;span class='sd'&gt;     * @return boolean True if no problem&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;save&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$tags&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt; &lt;span class='nv'&gt;$specificLifetime&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nv'&gt;$result&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;save&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt; &lt;span class='nv'&gt;$specificLifetime&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$result&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='c1'&gt;// Makes sure to always store the key for notMatchingTag cleaning mode&lt;/span&gt;
            &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;track_untagged&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nb'&gt;count&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$tags&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;

            &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nb'&gt;count&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='k'&gt;foreach&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$tags&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='nv'&gt;$tag&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                    &lt;span class='nv'&gt;$result&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;fetchAll&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
                                &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;select&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
                                    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;cacheid = ?&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
                                    &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tag = ?&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$tag&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
                    &lt;span class='p'&gt;);&lt;/span&gt;

                    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nv'&gt;$result&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;count&lt;/span&gt;&lt;span class='p'&gt;())&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                        &lt;span class='nv'&gt;$row&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;createRow&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;cacheid&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;tag&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='nv'&gt;$tag&lt;/span&gt;&lt;span class='p'&gt;));&lt;/span&gt;
                        &lt;span class='nv'&gt;$row&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;save&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
                    &lt;span class='p'&gt;}&lt;/span&gt;
                &lt;span class='p'&gt;}&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$result&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Remove a cache record&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param string $id Cache id&lt;/span&gt;
&lt;span class='sd'&gt;     * @return boolean True if no problem&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;remove&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_options&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;duplicates_ok&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nv'&gt;$where&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getAdapter&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;quoteInto&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;cacheid = ?&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;delete&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$where&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;remove&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$id&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Clean some cache records&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * Available modes are :&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;all&amp;#39; (default) =&amp;gt; remove all cache entries ($tags is not used)&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;old&amp;#39; =&amp;gt; remove too old cache entries ($tags is not used)&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;matchingTag&amp;#39; =&amp;gt; remove cache entries matching all given tags&lt;/span&gt;
&lt;span class='sd'&gt;     * ($tags can be an array of strings or a single string)&lt;/span&gt;
&lt;span class='sd'&gt;     * &amp;#39;notMatchingTag&amp;#39; =&amp;gt; remove cache entries not matching one of the given tags&lt;/span&gt;
&lt;span class='sd'&gt;     * ($tags can be an array of strings or a single string)&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param string $mode Clean mode&lt;/span&gt;
&lt;span class='sd'&gt;     * @param array $tags Array of tags&lt;/span&gt;
&lt;span class='sd'&gt;     * @return boolean True if no problem&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;clean&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$mode&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;CLEANING_MODE_ALL&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$tags&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;())&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$mode&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;CLEANING_MODE_MATCHING_TAG&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt;
             &lt;span class='nv'&gt;$mode&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;CLEANING_MODE_NOT_MATCHING_TAG&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

            &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nb'&gt;is_array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$tags&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;

            &lt;span class='c1'&gt;// Quote the tags and convert to a string&lt;/span&gt;
            &lt;span class='nv'&gt;$tags&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;array_map&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getAdapter&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;quote&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

            &lt;span class='c1'&gt;// Build the query for the desired matching mode&lt;/span&gt;
            &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$mode&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nx'&gt;Zend_Cache&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='na'&gt;CLEANING_MODE_MATCHING_TAG&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$items&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;select&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tag IN (?)&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$items&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;getTable&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;select&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tag NOT IN (?)&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;

            &lt;span class='k'&gt;foreach&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$items&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='nv'&gt;$item&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;remove&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$item&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;cacheid&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;

            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

        &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;clean&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$mode&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$tags&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;


    &lt;span class='sd'&gt;/**&lt;/span&gt;
&lt;span class='sd'&gt;     * Magic call handler to forward to the real backend the method calls&lt;/span&gt;
&lt;span class='sd'&gt;     *&lt;/span&gt;
&lt;span class='sd'&gt;     * @param string $method The method called&lt;/span&gt;
&lt;span class='sd'&gt;     * @param array $args The arguments used packed as an array&lt;/span&gt;
&lt;span class='sd'&gt;     * @return mixed&lt;/span&gt;
&lt;span class='sd'&gt;     */&lt;/span&gt;
    &lt;span class='k'&gt;public&lt;/span&gt; &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;__call&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$method&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$args&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;call_user_method_array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$method&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_backend&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$args&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=XztUn0fUTcI:LLI4royGXto:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=XztUn0fUTcI:LLI4royGXto:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=XztUn0fUTcI:LLI4royGXto:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=XztUn0fUTcI:LLI4royGXto:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=XztUn0fUTcI:LLI4royGXto:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/XztUn0fUTcI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/tags-emulation-zend-cache</feedburner:origLink></entry>
  
  <entry>
    <title>A really simple include filter for Drupal</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/7SvmePw-6PA/really-simple-include-filter-drupal" />
    <updated>2008-08-06T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/really-simple-include-filter-drupal</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve been using &lt;a href='http://texy.info/en/'&gt;Texy!&lt;/a&gt; lately to write in my Drupal powered blog, it&amp;#8217;s a great Markdown/Textile replacement and it even has a syntax highlighting addon which helps a lot to publish source code in the posts.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve found however a problem. I usually keep my source files in my subversion repository and sometimes I want to show the syntax highlighted code of one of those files in the post. I was getting tired to copy-pasting the contents so I&amp;#8217;ve implemented a dead simple Drupal input filter which dynamically includes a local or remote file as simple text in the content. I guess it can be useful too without Texy!&lt;/p&gt;

&lt;p&gt;The syntax is very easy to use and remember:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{include http://myserver.com/myfile.ext}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The module will use the Curl extension if available to fetch remote files, so it can work on hosts like DreamHost, which don&amp;#8217;t allow URLs via nomal file functions.&lt;/p&gt;

&lt;p&gt;Here is the .info&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;name = Include Filter
description = This module allows to include a text file in a node.
package = Filters
version = 1.0
core = 6.xCopy to clipboard&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the .module&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;includefilter_filter&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$op&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$delta&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$format&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$text&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;switch&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$op&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;list&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Include filter&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;description&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;t&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Allows to include a text file in the content. Give it a negative weight so it\&amp;#39;s processed before all other filters&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

        &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;prepare&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
        &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;process&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
            &lt;span class='nv'&gt;$text&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;preg_replace_callback&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;!{include\s+([^}]+)}!&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;_includefilter_replace&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$text&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$text&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

        &lt;span class='k'&gt;case&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;no cache&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='k'&gt;default&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$text&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;_includefilter_replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$m&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nb'&gt;preg_match&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;!^https?://!i&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='nb'&gt;function_exists&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;curl_init&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nv'&gt;$ch&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;curl_init&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
        &lt;span class='nb'&gt;curl_setopt&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$ch&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;CURLOPT_URL&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;
        &lt;span class='nb'&gt;curl_setopt&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$ch&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='nb'&gt;curl_setopt&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$ch&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;CURLOPT_CONNECTTIMEOUT&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;10&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='nv'&gt;$txt&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;curl_exec&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$ch&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='nb'&gt;curl_close&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$ch&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nv'&gt;$txt&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='o'&gt;@&lt;/span&gt;&lt;span class='nb'&gt;file_get_contents&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$txt&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;*IncludeFilter: Error including &amp;quot;&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='nv'&gt;$m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;quot;*&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$txt&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Remember to give this filter a negative weight so it gets executed before any other filter in your input format.&lt;/p&gt;
&lt;/blockquote&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=7SvmePw-6PA:oH-bjgwhuyA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=7SvmePw-6PA:oH-bjgwhuyA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=7SvmePw-6PA:oH-bjgwhuyA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=7SvmePw-6PA:oH-bjgwhuyA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=7SvmePw-6PA:oH-bjgwhuyA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/7SvmePw-6PA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/really-simple-include-filter-drupal</feedburner:origLink></entry>
  
  <entry>
    <title>RISON, a compact JSON specially suited for URIs</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/SstGZddEkVY/rison-compact-json-for-uris" />
    <updated>2008-07-28T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/rison-compact-json-for-uris</id>
    <content type="html">&lt;p&gt;I was looking for a way to efficiently pass data between cross-domain iframes using the location hash trick. The first thing that I checked was &lt;abbr title='JavaScript Object Notation'&gt;JSON&lt;/abbr&gt; but the payload gets huge when url encoded, then I tried with base64 encoding which helps but not very much. Finally I found &lt;a href='http://mjtemplate.org/examples/rison.html'&gt;RISON&lt;/a&gt; which in short is nothing more than a reformulation of &lt;abbr title='JavaScript Object Notation'&gt;JSON&lt;/abbr&gt;&amp;#8217;s control characters to make them more URI friendly.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;ll basically use &lt;code&gt;(&lt;/code&gt; instead of &lt;code&gt;{&lt;/code&gt;, &lt;code&gt;!(&lt;/code&gt; instead of &lt;code&gt;[&lt;/code&gt; or &lt;code&gt;!&lt;/code&gt; instead of &lt;code&gt;\&lt;/code&gt; to escape stuff. The result is quite good with savings of a 50% on average when url encoding the result. The only problem I had was that the source code no longer seems to be maintained and the only copy I could find was in the &lt;a href='http://code.google.com/p/jsonstore/source/browse/branches/0.3/jsonstore/paster_templates/htdocs/js/rison.js?r=89'&gt;repository of a project in google code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I&amp;#8217;ve implemented my own version taking as example &lt;a href='http://json.org/js.html'&gt;&lt;abbr title='JavaScript Object Notation'&gt;JSON&lt;/abbr&gt;&amp;#8217;s official reference implementation&lt;/a&gt; API and rolling in a really simple token based parser. It passes all the &lt;a href='http://mjtemplate.org/examples/rison.html#examples'&gt;test fragments from RISON&amp;#8217;s home page&lt;/a&gt; and the performance is quite good for moderately sized payloads.&lt;/p&gt;

&lt;p&gt;The code is licensed under the liberal &lt;a href='http://www.opensource.org/licenses/mit-license.php'&gt;MIT License&lt;/a&gt; and can be downloaded from my &lt;a href='http://svn.pollinimini.net/public/rison'&gt;subversion repository&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=SstGZddEkVY:jnnwFiVEuQw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=SstGZddEkVY:jnnwFiVEuQw:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=SstGZddEkVY:jnnwFiVEuQw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=SstGZddEkVY:jnnwFiVEuQw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=SstGZddEkVY:jnnwFiVEuQw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/SstGZddEkVY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/rison-compact-json-for-uris</feedburner:origLink></entry>
  
  <entry>
    <title>Nokia's N810 on the mail</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/ccPjgoinapU/nokia-n810" />
    <updated>2008-06-14T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/nokia-n810</id>
    <content type="html">&lt;p&gt;After being trying to get an &lt;a href='http://www.apple.com/iphone'&gt;iphone&lt;/a&gt; for a couple of months and haven&amp;#8217;t succeed at it, I sat down and did an extensive research on the market offerings for my needs. Finally I found what I needed and to my surprise it wasn&amp;#8217;t the phone with the Apple logo.&lt;/p&gt;

&lt;p&gt;I spend more than two hours each day on the train which gets absolutely packed at rush hours, so my plan to work on the laptop while traveling is not a feasible option (Even with my smallish &lt;a href='http://www.dell.com/content/products/productdetails.aspx/xpsnb_m1330'&gt;Dell XPS M1330&lt;/a&gt;). Checking email and rss feeds on my &lt;a href='http://www.sonyericsson.com/cws/products/mobilephones/overview/k800i'&gt;Sony Ericsson K800i&lt;/a&gt; cellphone works but with the huge amount of tunnels in the trip the data connection keeps falling and the screen is not that big as to make it a nice experience. So I decided to try with the Apple&amp;#8217;s phone which should offer a great experience while on the move with its large touch screen and the ability to sync imap accounts for offline reading of the inbox and nice rss reading. Since I couldn&amp;#8217;t obtain one I searched on the net for alternatives and I felt in love with Nokia&amp;#8217;s N810 internet tablet device.&lt;/p&gt;

&lt;p&gt;The &lt;a href='http://europe.nokia.com/A4568578'&gt;N810&lt;/a&gt; is not a smart phone, it just offers Wifi and Bluetooth radios so it needs to tether with a phone to access mobile data networks. It does offer however a wonderful touch screen sporting a 800×480 resolution with an amazing 225dpi (quite good for &lt;a href='http://www.fbreader.org/'&gt;ebook reading&lt;/a&gt;), a full qwerty keyboard and a Linux based (&lt;a href='http://maemo.org/'&gt;Maemo&lt;/a&gt;) operating system with a ton of available &lt;a href='http://maemo.org/downloads/OS2008'&gt;third party application and games&lt;/a&gt;. What I like the most about the device is that its environment is really open, which will allow me to tinker with it and suit it best to my needs.&lt;/p&gt;

&lt;p&gt;So yesterday I placed the order on Nokia&amp;#8217;s online shop for it and I should be enjoying this wonderful device next week. A big big big thanks to Cristina for giving me this great present!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ccPjgoinapU:07RoCgvrD5M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ccPjgoinapU:07RoCgvrD5M:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ccPjgoinapU:07RoCgvrD5M:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=ccPjgoinapU:07RoCgvrD5M:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ccPjgoinapU:07RoCgvrD5M:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/ccPjgoinapU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/nokia-n810</feedburner:origLink></entry>
  
  <entry>
    <title>A web development environment (III) - Firefox</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/Ab0rQQS8C3o/web-development-environment-3" />
    <updated>2007-12-26T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/web-development-environment-3</id>
    <content type="html">&lt;p&gt;Firefox is a great browser and is also a great development tool in itself. There are some problems though with the numerous extension available to developers. They are a great resource when programming but they slow down (and in some scenarios they might even break) our normal web browsing.&lt;/p&gt;

&lt;p&gt;So the idea is to have a normal Firefox installation to use as our browser and then a separate install (and profile) used only for development purposes. This way we can install tons of development related addons without worrying about slowing down our normal browsing. Of course this is only useful if you use Firefox as your primary browser.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Download the &lt;a href='http://www.getfirefox.com/'&gt;Firefox installer&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Launch the installer&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Set the destination folder to &lt;code&gt;c:\dev\Develfox&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Uncheck the options to create shortcuts on desktop, start menu…&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Uncheck the option to launch Firefox on finishing the setup&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Go to the installation directory and start a command prompt there&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Run Firefox with the following command: &lt;code&gt;firefox.exe -no-remote -ProfileManager&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new profile and name it &lt;em&gt;Devel&lt;/em&gt;&lt;/li&gt;

&lt;li&gt;Exit the profile manager&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Create a new batch file name &lt;code&gt;develfox.bat&lt;/code&gt; with the following contents. It’ll copy on each run the firefox executable to &lt;code&gt;develfox.exe&lt;/code&gt; so we can tell it apart from our normal browser on the task manager (we copy it on each run so that automatic updates are correctly applied).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@echo off
copy &amp;quot;c:\dev\develfox\firefox.exe&amp;quot; &amp;quot;c:\dev\develfox\develfox.exe&amp;quot; &amp;gt; null
start &amp;quot;&amp;quot; &amp;quot;c:\dev\develfox\develfox.exe&amp;quot; -no-remote -P &amp;quot;Devel&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Still on the installation directory go to the &lt;code&gt;chrome&lt;/code&gt; folder and create in there a directory named &lt;code&gt;icons&lt;/code&gt; and inside that one another called &lt;code&gt;default&lt;/code&gt;. Put in there a custom icon with the name &lt;code&gt;main-window.ico&lt;/code&gt; to be used as the application icon. Check out &lt;a href='http://www.iconbase.com/'&gt;IconBase&lt;/a&gt; for some nice ones.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a shortcut on your desktop or another suitable place and use the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Target: &lt;code&gt;c:\dev\develfox\develfox.bat&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Start in: &lt;code&gt;c:\dev\develfox&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Change the icon to &lt;code&gt;c:\dev\develfox\chrome\icons\default\main-window.ico&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Launch the shortcut to execute our new Firefox installation. It’ll be a vanilla one so now it’s time to install our development addons ( Firebug, Webdev toolbar, Yslow, Clearcache, Venkman… ) and also a custom theme so we can easily know in which firefox we are at each moment.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;To further customize our new Firefox installation we can install the &lt;a href='http://addons.mozilla.org/en-US/firefox/addon/31'&gt;Firesomething&lt;/a&gt; addon, which allows to change the window title to anything we want.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='update_20081103'&gt;Update 2008–11–03&lt;/h2&gt;

&lt;p&gt;A great extension for Flash/Flex development is &lt;a href='http://www.sephiroth.it/firefox/flash_switcher/'&gt;FlashSwitcher&lt;/a&gt; which allows to easily change the Flash player version used in Firefox. One problem though is that it&amp;#8217;ll interfere with your default Firefox installation. To solve this you can edit its settings dialog and point the &lt;em&gt;Firefox Plugin directory&lt;/em&gt; to &lt;code&gt;c:\dev\develfox\plugins&lt;/code&gt; instead of the default location. This way the Flash player changes will only affect our development firefox installation.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ab0rQQS8C3o:pO7nYDOHnAI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ab0rQQS8C3o:pO7nYDOHnAI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ab0rQQS8C3o:pO7nYDOHnAI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=Ab0rQQS8C3o:pO7nYDOHnAI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Ab0rQQS8C3o:pO7nYDOHnAI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/Ab0rQQS8C3o" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/web-development-environment-3</feedburner:origLink></entry>
  
  <entry>
    <title>A web development environment (II) - Cygwin</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/ag56cOXKb-4/web-development-environment-2" />
    <updated>2007-12-26T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/web-development-environment-2</id>
    <content type="html">&lt;p&gt;Following with the series I will introduce in this chapter &lt;a href='http://www.cygwin.com/'&gt;Cygwin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cygwin is an excellent collection of Unix utilities and programs ported to Windows. While its &lt;em&gt;emulation&lt;/em&gt; of an Unix like environment is quite good I actually don’t use it. I install it just for the helpful utilities it has. Although I do occasionally use its shell to perform some command line tasks which on Windows’ cmd.exe would be a real nightmare to perform.&lt;/p&gt;

&lt;p&gt;Lets set it up and then we can see some tips and tricks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Download the &lt;a href='http://www.cygwin.com/'&gt;Cygwin installer&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Move the installer (setup.exe) to &lt;code&gt;c:\dev\cygwin&lt;/code&gt; and launch it&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Set the &lt;em&gt;Root Directory&lt;/em&gt; to &lt;code&gt;c:\dev\cygwin&lt;/code&gt; and the &lt;em&gt;Local Package Directory&lt;/em&gt; to &lt;code&gt;c:\dev\cygwin\packages&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Choose at least the following packages to install. You won’t probably need all of them but in my experience these are the most commonly used and they don’t take much space actually:&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;Admin&lt;/dt&gt;

&lt;dd&gt;shutdown&lt;/dd&gt;

&lt;dt&gt;Archive&lt;/dt&gt;

&lt;dd&gt;unzip, zip&lt;/dd&gt;

&lt;dt&gt;Base&lt;/dt&gt;

&lt;dd&gt;bash, findutils, grep, gzip, run, tar, sed, termcap, terminfo&lt;/dd&gt;

&lt;dt&gt;Database&lt;/dt&gt;

&lt;dd&gt;sqlite3&lt;/dd&gt;

&lt;dt&gt;Devel&lt;/dt&gt;

&lt;dd&gt;binutils, automake, cvs, cygport, gcc, make, subversion&lt;/dd&gt;

&lt;dt&gt;Editors&lt;/dt&gt;

&lt;dd&gt;nano, vim&lt;/dd&gt;

&lt;dt&gt;Graphics&lt;/dt&gt;

&lt;dd&gt;ImageMagick&lt;/dd&gt;

&lt;dt&gt;Interpreters&lt;/dt&gt;

&lt;dd&gt;m4, perl, python, ruby&lt;/dd&gt;

&lt;dt&gt;Net&lt;/dt&gt;

&lt;dd&gt;curl, openssh, openssl, rsync&lt;/dd&gt;

&lt;dt&gt;Shells&lt;/dt&gt;

&lt;dd&gt;bash, bash-completion&lt;/dd&gt;

&lt;dt&gt;Text&lt;/dt&gt;

&lt;dd&gt;less, tidy&lt;/dd&gt;

&lt;dt&gt;Utils&lt;/dt&gt;

&lt;dd&gt;bzip2, cygutils, diffutils, gnupg, patch, scree&lt;/dd&gt;

&lt;dt&gt;Web&lt;/dt&gt;

&lt;dd&gt;cadaver, curl, httping, links, lynx, wget&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Now wait for all packages to download and install (it will take a while)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Once the installation is complete we can launch the Cygwin system by running &lt;code&gt;c:\dev\cygwin\cygwin.bat&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;On the first run it’ll create a new configuration and home directory for our user. Follow the instructions given on the terminal to complete the installation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, so Cygwin is now setup and it’s time to learn a few tips.&lt;/p&gt;

&lt;p&gt;On a standard installation Cygwin will create a home directory for the user in &lt;code&gt;c:\dev\cygwin\home\[USER]&lt;/code&gt;. However we might want to re-use our Windows folder so we have a unique location for our stuff. To do it we just need to create an environment variable (in &lt;em&gt;System Preferences&lt;/em&gt;) called &lt;code&gt;HOME&lt;/code&gt; with the path to our profile folder (&lt;code&gt;c:\Users\[USER]&lt;/code&gt; in Vista). Now we have to edit &lt;code&gt;/etc/passwd&lt;/code&gt; and change the home folder to our Windows profile one (&lt;code&gt;/cygdrive/c/Users/[USER]&lt;/code&gt;), we can move the contents of the old home folder to the new one with the following commands:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mv /home/[USER]/* /cygdrive/c/Users/[USER]/.
$ mv /home/.* /cygdrive/c/Users/[USER]/.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By default the Windows drive letters are accessible in &lt;code&gt;/cygdrive/[DRIVE]&lt;/code&gt;, that is ok but it’s used often so we can save a few key strokes by creating symlinks at the root of the file system. Create one for each of your drive letters so you can access them as &lt;code&gt;/[DRIVE]/my/path/to/a/file&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ln -s /cygdrive/c /c&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As we have seen Cygwin uses Unix like paths so to launch Windows programs from the shell we have to make an extra step and that is to convert between paths. Fortunately there is a little tool called &lt;code&gt;cygpath&lt;/code&gt;. When used without modifiers it will translate a Windows path to a Cygwin one and when used with the &lt;strong&gt;-w&lt;/strong&gt; or the &lt;strong&gt;-m&lt;/strong&gt; modifiers it will do the opposite conversion.&lt;/p&gt;

&lt;p&gt;Another nice tool is cygstart which launches a program (or the default program associated with a document). The good about it is that it will launch the program and detach the process from the console.&lt;/p&gt;

&lt;p&gt;For commonly used programs it’s a bit uncomfortable to use &lt;code&gt;cygpath&lt;/code&gt; and &lt;code&gt;cygstart&lt;/code&gt;, like for example to launch our favourite text editor. In this example I’m going to use Notepad as an example. We just have to change our bash init script (&lt;code&gt;~/.bashrc&lt;/code&gt;) to include a function to launch Notepad easily from the command line. Add the following to your &lt;code&gt;.bashrc&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;notepad () {
    cygstart &amp;quot;c:/Windows/System32/notepad.exe&amp;quot; &amp;quot;`cygpath -w $1`&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can edit the contents of a text file just doing &lt;code&gt;notepad /var/log/setup.log&lt;/code&gt;. This is a great way to really integrate Cygwin with Windows, which actually makes the Cygwin system ready for real work.&lt;/p&gt;

&lt;p&gt;Another useful utility is &lt;a href='http://www.skamphausen.de/cgi-bin/ska/CDargs'&gt;cdargs&lt;/a&gt; which while not an official part of the Cygwin system can be compiled from source. To install it we just have to download its &lt;a href='http://www.skamphausen.de/downloads/cdargs'&gt;latests source tarball&lt;/a&gt; and unpack it into your Cygwin home directory. Then issue the following commands:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd cdargs-1.XX
$ ./configure
$ make
$ make install
$ cp contrib/cdargs-bash.sh /etc/profile.d/.
$ source /etc/profile.d/cdargs-bash.sh&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Explaining how to use this tool is beyond the scope of this article. There is a nice &lt;a href='http://www.linux.com/articles/114073'&gt;mini tutorial at Linux.com&lt;/a&gt; and &lt;a href='http://www.google.com/search?q=cdargs%2Btutorial'&gt;Google&lt;/a&gt; will give you plenty of information about this tool.&lt;/p&gt;

&lt;p&gt;There is a lot of software compatible with Cygwin beyond the packages included in the official repository. The &lt;a href='http://cygwinports.dotsrc.org/'&gt;Cygwin Ports project&lt;/a&gt; offers a few dozens of applications already compiled and ready to be installed. It’s well worth a look. Besides there are many Unix/Linux applications which can be compiled to be used in Cygwin even if they don’t redistribute the binary packages.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ag56cOXKb-4:s6aOK2rvGmY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ag56cOXKb-4:s6aOK2rvGmY:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ag56cOXKb-4:s6aOK2rvGmY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=ag56cOXKb-4:s6aOK2rvGmY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ag56cOXKb-4:s6aOK2rvGmY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/ag56cOXKb-4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/web-development-environment-2</feedburner:origLink></entry>
  
  <entry>
    <title>A web development environment (I) - Introduction</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/1opbNsbQLs4/web-development-environment-1" />
    <updated>2007-12-26T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/web-development-environment-1</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;This will be a series of posts dedicated to document my current development setup. This setup tries to be the one of a Ninja. It won’t end up with a bunch of boring application windows typical of a bald engineer. It also won’t be a group of black terminal windows running vi as a pseudo operating system like the average geek wannabe. I’m in the search of the Ninja feeling, with white on black text editors, translucent terminals and a dose of eye candy so that I feel special without having to resort to browsing youtube with Lynx.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After many years I am finally happy with my current development setup. It fits my needs and this series of articles should serve myself as a reminder on how to setup the different pieces. However I guess that it will also be of inspiration for other developers who haven’t already found their peace of mind with their environment.&lt;/p&gt;

&lt;p&gt;I’ll focus on Microsoft Windows systems but most of the stuff can be easily implemented in other operating systems. Actually much of the things I do for windows come standard in several operating system distributions, it’s just that I happen to like Windows (which obviously harms my geek status).&lt;/p&gt;

&lt;p&gt;The main building blocks for this environment are the following ones:&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;Cygwin&lt;/dt&gt;

&lt;dd&gt;A collection of very useful Unix utilities for Windows.&lt;/dd&gt;

&lt;dt&gt;coLinux&lt;/dt&gt;

&lt;dd&gt;Wonderful &lt;em&gt;virtualization&lt;/em&gt; software to run Linux side by side Windows.&lt;/dd&gt;

&lt;dt&gt;Debian&lt;/dt&gt;

&lt;dd&gt;The only Linux distro I know a bit about. It’s fantastic so I don’t have the need to search for a better one.&lt;/dd&gt;

&lt;dt&gt;PHP5&lt;/dt&gt;

&lt;dd&gt;Currently the programming language of my choice.&lt;/dd&gt;

&lt;dt&gt;Console2&lt;/dt&gt;

&lt;dd&gt;An excellent terminal emulator with lots of eye candy.&lt;/dd&gt;

&lt;dt&gt;Firefox&lt;/dt&gt;

&lt;dd&gt;The browser that came to rule them all.&lt;/dd&gt;

&lt;dt&gt;A lightweight text editor&lt;/dt&gt;

&lt;dd&gt;Everyone has its favorite&lt;/dd&gt;

&lt;dt&gt;A heavy IDE&lt;/dt&gt;

&lt;dd&gt;Komodo and Eclipse to the rescue&lt;/dd&gt;

&lt;dt&gt;Several utilities to ease our lives&lt;/dt&gt;

&lt;dd&gt;TortoiseSVN, kdiff3, wincachegrind, total commander…&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;Before we begin I would like to note the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All tools are installed in &lt;code&gt;C:\dev&lt;/code&gt;. I don’t like polluting the standard Windows installation with the development tools. Besides, it allows to easily backup most of the environment.&lt;/li&gt;

&lt;li&gt;I’m using a 32bit version of Windows Vista since coLinux is not compatible with 64bit versions.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=1opbNsbQLs4:8eQevupkj6U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=1opbNsbQLs4:8eQevupkj6U:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=1opbNsbQLs4:8eQevupkj6U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=1opbNsbQLs4:8eQevupkj6U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=1opbNsbQLs4:8eQevupkj6U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/1opbNsbQLs4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/web-development-environment-1</feedburner:origLink></entry>
  
  <entry>
    <title>Xdebug bookmarklet</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/6emSfRTvSKA/xdebug-bookmarklet" />
    <updated>2007-11-26T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/xdebug-bookmarklet</id>
    <content type="html">&lt;p&gt;Nothing really new since there is already a &lt;a href='https://addons.mozilla.org/en-US/firefox/addon/3960'&gt;firefox extension&lt;/a&gt; which does just the same, but I also wanted to support other browsers.&lt;/p&gt;

&lt;p&gt;So this bookmarklet toggles the cookie Xdebug uses to check if it should debug the running script or not!.&lt;/p&gt;
&lt;p&gt;
    &lt;a href='javascript:(function(){var idekey=&amp;apos;&amp;apos;, minutes=10, exp=new Date(); document.title=&amp;apos;Xdebug disabled&amp;apos;; if(document.cookie.match(/(^|;)\s*XDEBUG_SESSION=/)){minutes=-minutes;} else { if(!idekey) idekey=prompt(&amp;apos;Set the IDE key for this debugging session if needed (cancel to disable)&amp;apos;,&amp;apos;default&amp;apos;); if(idekey===null){minutes=-minutes}else{document.title=&amp;apos;Xdebug enabled&amp;apos;}} exp.setTime(exp.getTime()+minutes*60*1000);document.cookie=&amp;apos;XDEBUG_SESSION=&amp;apos;+(idekey?idekey:&amp;apos;default&amp;apos;)+&amp;apos;;expires=&amp;apos;+exp.toGMTString()}())'&gt;Toggle Xdebug&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Drag it to your bookmarks (or favorites or whatever your browser calls it) toolbar so it&amp;#8217;s easy to access. Assign it a keyboard shortcut, if your browser has that function, and you&amp;#8217;re done.&lt;/p&gt;

&lt;p&gt;By default it&amp;#8217;ll prompt for the &lt;em&gt;idekey&lt;/em&gt; to be used by Xdebug, it&amp;#8217;s a good idea to modify the &lt;em&gt;idekey&lt;/em&gt; variable at the start of the bookmarklet&amp;#8217;s source with your &lt;em&gt;idekey&lt;/em&gt; or with &lt;em&gt;default&lt;/em&gt; if you&amp;#8217;re not using a DBGp proxy.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6emSfRTvSKA:BnDKe6TB1Vs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6emSfRTvSKA:BnDKe6TB1Vs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6emSfRTvSKA:BnDKe6TB1Vs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=6emSfRTvSKA:BnDKe6TB1Vs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=6emSfRTvSKA:BnDKe6TB1Vs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/6emSfRTvSKA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/xdebug-bookmarklet</feedburner:origLink></entry>
  
  <entry>
    <title>Introducing DBGp Path Mapper intercepting proxy</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/TLlwhdUcWaA/introducing-dbgp-path-mapper-intercepting-proxy" />
    <updated>2007-11-25T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/introducing-dbgp-path-mapper-intercepting-proxy</id>
    <content type="html">&lt;p&gt;My current IDE of choice, &lt;a href='http://www.activestate.com/'&gt;Komodo&lt;/a&gt;, brings native support for the &lt;a href='http://xdebug.org/docs-dbgp.php'&gt;DBGp protocol&lt;/a&gt; to debug source code either locally or from a remote server. &lt;del&gt;It has however some
issues with its path mapping implementation&lt;/del&gt;&lt;sup id='fnref:1'&gt;&lt;a href='#fn:1' rel='footnote'&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Since it’s not the first time I stumbled upon this kind of issue (my previous &lt;a href='http://www.eclipse.org/pdt'&gt;Eclipse PDT&lt;/a&gt; experience was troublesome too) I finally tried to solve it. The solution is an intercepting proxy server which listen for connection from the debugger to modify the messages it sends to the IDE with custom path mappings.&lt;/p&gt;

&lt;p&gt;To define the path mappings we use a file with a set of paths on each line. The path tuples are separated by the =&amp;gt; operator, placing the path understood by the debugger on the left side and on the right the path as understood by the IDE. The file looks like this.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Mapping for projects
file:///var/www/projects =&amp;gt; file:///c:/Users/DrSlump/projects
# this one is for my subdomains
file:///var/www/subdomains =&amp;gt; file:///c:/subdomainsCopy to clipboard&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the path mappings are case insensitive to avoid problems on Windows.&lt;/p&gt;

&lt;p&gt;To run the path mapper server we just need to call it from a terminal like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ php5 dbgp-mapper.php -i 192.168.0.5 -m dbgp.mapCopy to clipboard&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;strong&gt;-i&lt;/strong&gt; option specifies the IP or host of the computer where the IDE is running, while the &lt;strong&gt;-m&lt;/strong&gt; option points to the file where the path mappings are defined. There are also other options which you can check by seeing the built in help using the &lt;strong&gt;-h&lt;/strong&gt; argument.&lt;/p&gt;

&lt;p&gt;By default it will bind itself to the port 9000, which is DBGp default one, so if you are running this on the same computer as your IDE you will have to change the port either in this tool or on your IDE.&lt;/p&gt;

&lt;p&gt;The source is available via &lt;a href='http://svn.pollinimini.net/public/dbgp-mapper'&gt;this subversion repository&lt;/a&gt;&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id='fn:1'&gt;
&lt;p&gt;It seems that Komodo&amp;#8217;s uri mapping works properly after version 4.2.0. In my case I was having problems but after rebooting the system it started to work properly.&lt;/p&gt;
&lt;a href='#fnref:1' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TLlwhdUcWaA:xztPMe-_nUI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TLlwhdUcWaA:xztPMe-_nUI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TLlwhdUcWaA:xztPMe-_nUI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=TLlwhdUcWaA:xztPMe-_nUI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TLlwhdUcWaA:xztPMe-_nUI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/TLlwhdUcWaA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/introducing-dbgp-path-mapper-intercepting-proxy</feedburner:origLink></entry>
  
  <entry>
    <title>TextMate, the myth</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/uY87dEVoAow/textmate-myth" />
    <updated>2007-11-02T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/textmate-myth</id>
    <content type="html">&lt;p&gt;Source code editing and programming tools in general are one of those things I like to be up to date with, you never know when you’re going to find a killer tool which will boost your productivity.&lt;/p&gt;

&lt;p&gt;For a couple of years I keep hearing about an awesome editor for Macs called TextMate. People even comment on forums and blogs that they are thinking to switch to Mac just to use it.&lt;/p&gt;

&lt;p&gt;Well, I switched to Mac a few weeks ago and one of the first things I installed was this TextMate editor. Given all the hype around it I thought it was going to be my new favourite editor. However there is a lot of myth around this software. For the last year I’ve been using Eclipse on Windows as my heavy work IDE with Notepad++ as casual editor for quick operations. Now on the Mac Eclipse runs quite slowly so I’ve been using TextMate a lot in the last days and while it’s a great replacement for Notepad++ it doesn’t come close to a real IDE. The Bundles are nice and expose a lot of possibilities but they are useless to work on a big project.&lt;/p&gt;

&lt;p&gt;When you have to deal with a few hundreds library files (Zend Framework, Doctrine, Pear…) plus another few hundreds of the project then there is nothing else to do that to use a real IDE with professional tools like integrated debugger, a real code parser, a code explorer and powerful refactoring tools (at least a good find and replace dialog with regular expression support). Then there are some extras like bracket pairing, code versioning, code formatting and smart indentation.&lt;/p&gt;

&lt;p&gt;Sure some of you could argue that TextMate’s power is on its snippets/bundles customization but lets be serious. I don’t mind writing function or class constructs continuously, it can get tedious but what really hurts your performance is having to leave the file your are editing because you don’t remember the exact spelling of an obscure method from a rarely used class, or you can’t recall what was the order of the arguments for that function that you checked just two hours ago.&lt;/p&gt;

&lt;p&gt;Given that Eclipse is running like a dog on my system I’ve searched for an alternative and to my surprise I’ve found a killer one. ActiveState’s Komodo IDE, which I had trialed a few months ago in Windows but didn’t really paid attention to it. It’s dialogs are a bit buggy, the default colour schemes are quite ugly, it takes ages to load, is very expensive and it’s not the easiest to configure to a point where it’s useable but… it’s really customizable and has a ton of features out of the box. Moreover there is Komodo Edit which is free but doesn’t have an integrated debugger, so I’m going to settle on it and will keep Eclipse for remote debugging. Let’s see if ActiveState drops the price so it can get more popular. By the way, it also has support for code snippets and macros which can make most of the stuff that TextMate’s bundles can do.&lt;/p&gt;

&lt;p&gt;So right now, I’m using Komodo IDE and TextMate. When the trial periods of both are over I’ll have a combination of Komodo Edit, Eclipse and Smultron for the fast editing.&lt;/p&gt;

&lt;p&gt;PS: Excuse the lack of links… google is your friend&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=uY87dEVoAow:7e5E_SU6rJY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=uY87dEVoAow:7e5E_SU6rJY:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=uY87dEVoAow:7e5E_SU6rJY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=uY87dEVoAow:7e5E_SU6rJY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=uY87dEVoAow:7e5E_SU6rJY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/uY87dEVoAow" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/textmate-myth</feedburner:origLink></entry>
  
  <entry>
    <title>Automatic login to SSH with Putty</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/vSlYaCyQ9qk/automatic-login-ssh-putty" />
    <updated>2007-07-10T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/automatic-login-ssh-putty</id>
    <content type="html">&lt;p&gt;Go to the &lt;a href='http://www.chiark.greenend.org.uk/~sgtatham/putty'&gt;PuTTY homepage&lt;/a&gt; and download PuTTY, PuTTYgen and Pageant. Put them in an easily accessible directory like &lt;code&gt;%PROGRAMFILES%\Putty&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Launch &lt;code&gt;puttygen.exe&lt;/code&gt; and click on &lt;em&gt;Generate&lt;/em&gt;, then move your mouse in the space below the progress bar to create some entropy for the key randomness. Once the key is generated lets complete the available fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Key comment&lt;/strong&gt; is just a comment so anything will do, putting username-putty seems quite logical.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Key passphrase&lt;/strong&gt; is actually a password to unlock the key. Put something complex in here but make sure you’ll remember it in the future!!!&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Confirm passphrase&lt;/strong&gt;, here you just input again the password to confirm you know which is it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now click on &lt;em&gt;Save private key&lt;/em&gt; to store it permanently on your hard disk. Choose a secure place for it, I can’t strength enough how important is that this key remains secret. A good location could be &lt;code&gt;%USERPROFILE%\ssh\putty.ppk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Do not close PuTTYgen just yet, we need to copy the public key to our server (or servers). Connect to the remote server with your username and password as normal, go to your home directory and create a directory named &lt;code&gt;.ssh&lt;/code&gt; if it doesn’t exists already. Create a text file named &lt;code&gt;authorized_keys2&lt;/code&gt; in the &lt;code&gt;.ssh/&lt;/code&gt; directory, inside that file copy the public key from PuTTYgen in a single line, save the file and exit the shell. Make sure the &lt;code&gt;.ssh&lt;/code&gt; directory and its contents are only accessible by you (&lt;code&gt;chmod -R og= .ssh&lt;/code&gt;). Repeat this step for each server you want to access with your public key.&lt;/p&gt;

&lt;p&gt;The next step is to configure PAgeant (PuTTY Authentication Agent) to automatically start with Windows. Just create a shortcut in your &lt;em&gt;Startup folder&lt;/em&gt;, the target should be something similar to &lt;code&gt;%PROGRAMFILES%\Putty\pageant.exe &amp;quot;%USERPROFILE%\ssh\putty.ppk&amp;quot;&lt;/code&gt;, change it to suit the paths you’ve used.&lt;/p&gt;

&lt;p&gt;Double click it to avoid having to restart to launch it, a small pop-up window should show asking for your passphrase, type it and press Ok. If you have typed the correct passphrase a small blueish icon should show on you system tray, right click it to start a new session or launch a pre-configured one. If everything is allright PAgeant should take care of authenticate you.&lt;/p&gt;

&lt;p&gt;Just a simple tip in case you don’t know, you can specify an username together with the server address by using this syntax: &lt;em&gt;username@server.com&lt;/em&gt;. This way the authentication is completely automatic.&lt;/p&gt;

&lt;p&gt;There are also another couple of great companion tools from PuTTY: PSCP and PSFTP. The first is a command line tool to transfer files securely between computers, the second is a text mode FTP client using a secure SSH connection. Specially the PSCP can be handy to be used in batch files to automatize some tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PLEASE READ:&lt;/strong&gt; Be careful with using public keys authentication to connect to a server. The steps I described are ok if you have the access to your computer restricted, do not leave PAgeant running while you’re away from your computer!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=vSlYaCyQ9qk:I5pQmCzIX44:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=vSlYaCyQ9qk:I5pQmCzIX44:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=vSlYaCyQ9qk:I5pQmCzIX44:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=vSlYaCyQ9qk:I5pQmCzIX44:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=vSlYaCyQ9qk:I5pQmCzIX44:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/vSlYaCyQ9qk" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/automatic-login-ssh-putty</feedburner:origLink></entry>
  
  <entry>
    <title>Los sitios web deberían ser fáciles de crear</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/_pSv79_e01Q/los-sitios-web-deberian-ser-faciles-de-crear" />
    <updated>2007-07-03T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/los-sitios-web-deberian-ser-faciles-de-crear</id>
    <content type="html">&lt;p&gt;Este es un post &lt;em&gt;filosófico&lt;/em&gt; que llevo algún tiempo preparando para aclarar mis ideas. Como dice el título, &lt;em&gt;los sitios web (aplicaciones web incluidas) deberían ser fáciles de crear&lt;/em&gt;. El sitio web típico tiene unas pocas docenas de páginas, un par de formularios y sindicación RSS como mucho. No parece que sea algo muy complejo, menos aun si tenemos en cuenta que la infraestructura para que funcionen es asequible, contrastada y potente. Algunos (yo me incluía en ese grupo hasta hace unos meses) culpan el hecho de la complejidad de crear un buen sitio web a lo enrevesado del entorno, un entorno no controlado como es un navegador web, donde las sutiles diferencias entre versiones y marcas suponen elevar exponencialmente la complejidad de la creación. La realidad en mi opinión es distinta.&lt;/p&gt;

&lt;p&gt;El paradigma de programación más utilizado actualmente para el desarrollo de sitios web es el popular MVC (Model-View-Controller), algo que ya tiene unos cuantos años pero que solo en los últimos dos o tres se ha empezado a utilizar para el desarrollo de webs simples. La idea de ese concepto es que dividimos el desarrollo en tres capas diferenciadas. El Modelo se encarga de hacer el acceso a los datos uniforme, la lógica de negocio queda encapsulada en esta capa. La Vista se encarga de la presentación de la información, formateando los datos obtenidos del Modelo de una manera atractiva para el visitante. Por último el Controlador es quien controla quien puede ver que y bajo que circunstancias, además de ser el pegamento que une todas las piezas. Pues bien, resulta que para un sitio web normalito no necesitamos tantas capas, porque la realidad es que esas capas ya existen en la infraestructura utilizada, como por ejemplo con un stack LAMP.&lt;/p&gt;

&lt;p&gt;Apache no es más que un Controlador, MySQL es un Modelo y los ficheros HTML son la Vista. Estamos de acuerdo en que esa infraestructura es muy genérica y que trabajar con ella es como construir una casa con herramientas manuales. Pero por que ocultar totalmente esas herramientas para substituirlas por otras nuevas más lentas y menos flexibles? Hablemos de REST, la filosofía detrás de la World Wide Web.&lt;/p&gt;

&lt;p&gt;REST es el diseño en el que se modeló la web, se basa en que hay un conjunto de recursos identificados globalmente (la conocida URL) que pueden obtenerse en diferentes formatos (HTML, XML, PDF…). El diseño es realmente elegante y lo mejor de todo es que es algo probado y contrastado durante casi dos décadas. Mi conclusión es que si hacemos un sitio web este ha de hacerse en base a los principios básicos del medio donde reside, de lo contrario sería como intentar hacer un barco para ir por una carretera, seguro que podemos añadir ruedas pero seguirá pareciendo un barco en vez de un coche.&lt;/p&gt;

&lt;p&gt;Así que juntando lo comentado arriba sobre LAMP como framework con el diseño REST, podemos obtener un sistema muy potente, flexible y fácil de utilizar. Para empezar tenemos que aprovechar la infraestructura disponible, y aprovecharla con criterio, como por ejemplo no almacenar las páginas HTML en una base de datos sino en el disco. A primera vista vemos que solo con el servidor web, la base de datos y el HTML estamos como hace 10 años, editando los ficheros con un editor y subiéndolos por FTP para publicarlos. Necesitamos algo que complete esas herramientas y ese algo son los lenguajes interpretados, ya sea PHP, Perl, Python, Java o Ruby. Estos lenguajes nos permitirán crear el pegamento necesario para ofrecer soluciones modernas de una manera simple y escalable. La idea es volver unos 5 años hacia atrás y retomar la costumbre de hacer una web con ladrillos, utilizando scripts prácticamente independientes para crearla. Después de todo PHPNuke fue popular pero no era la solución, aunque detrás de él hayan aparecido miles de sucesores intentando solucionar sus problemas, que lo único que han conseguido es ocultar esos problemas con capas y capas de complejidad añadida.&lt;/p&gt;

&lt;p&gt;En un próximo artículo comentaré sobre una posible implementación de todo esto. La idea básica es la de quitar capas de complejidad de nuestros scripts para poder concentrarnos en la funcionalidad y el contenido, eliminando posibles puntos negros de errores y aprovechando la escalabilidad inherente a la web.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_pSv79_e01Q:AKhMmgPSeVQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_pSv79_e01Q:AKhMmgPSeVQ:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_pSv79_e01Q:AKhMmgPSeVQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=_pSv79_e01Q:AKhMmgPSeVQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_pSv79_e01Q:AKhMmgPSeVQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/_pSv79_e01Q" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/los-sitios-web-deberian-ser-faciles-de-crear</feedburner:origLink></entry>
  
  <entry>
    <title>Rectangle Packing (2D packing)</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/_xiAZ7h9ABE/rectangle-packing-2d-packing" />
    <updated>2007-06-15T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/rectangle-packing-2d-packing</id>
    <content type="html">&lt;p&gt;I’m working on a little thing which I don’t want to speak about just now, lets see if I can get it to do what I want first before making it public. However for that project I needed to pack several small rectangles of varying dimensions into a bigger one without them overlapping.&lt;/p&gt;

&lt;p&gt;At first it seem like an easy task but the more I thought about it the more difficult it was. After a bit of research I found out that until today this seems to be a non resolved problem, there are algorithms which offer a pretty decent approximation to the optimal result though. The problem is commonly known as the Bin Packing problem and in this case I needed to work with two dimensional objects (rectangles) so it gets a lot more complicated.&lt;/p&gt;

&lt;p&gt;After more googling I found an article by Jim Scott with pseudo code to solve a similar problem, the article explains on how to pack several lightmaps into a single texture. It was the easiest to understand algorithm I had found so I went ahead and implemented it in PHP. I had it in a few minutes but I wanted to fine tune the results by feeding it the rectangles by different sorting criteria, since it seems to be a good way to achieve the best results. Well, I got tired to slowly generating the image in PHP to check the results with every minor variation so I implemented a JavaScript version which allows to see the result in real time.&lt;/p&gt;

&lt;p&gt;This algorithm can be used for a wide variety of problems, from packaging small sprites in a big image to allocate tasks in complex projects (use the width for the team developers and the height for the time).&lt;/p&gt;

&lt;p&gt;A simple usage example could be as follows:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;coords&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='nx'&gt;packer&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;NETXUS&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;RectanglePacker&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='mi'&gt;512&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;512&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;&amp;lt;&lt;/span&gt;&lt;span class='nx'&gt;images&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nx'&gt;coords&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;packer&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;findCoords&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;images&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;width&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;images&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;height&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nx'&gt;alert&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Image of &amp;#39;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;images&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;width&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;x&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;images&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;height&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt;
         &lt;span class='s1'&gt;&amp;#39; allocated at &amp;#39;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;coords&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;x&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;x&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;coords&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;y&lt;/span&gt;
    &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I’ve put up a &lt;a href='/demos/RectanglePacker.html'&gt;demo&lt;/a&gt; so you can try it and see the results with different parameters. Tip: the best results seems to be with the blocks sorted by the magic method and reversed.&lt;/p&gt;

&lt;p&gt;You can &lt;a href='/files/RectanglePacker.js'&gt;download the source code from this link&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_xiAZ7h9ABE:PCJBBfieqFo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_xiAZ7h9ABE:PCJBBfieqFo:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_xiAZ7h9ABE:PCJBBfieqFo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=_xiAZ7h9ABE:PCJBBfieqFo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=_xiAZ7h9ABE:PCJBBfieqFo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/_xiAZ7h9ABE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/rectangle-packing-2d-packing</feedburner:origLink></entry>
  
  <entry>
    <title>Hex2Dec and Dec2Hex</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/cGNqk_FRd5k/hex2dec-dec2hex" />
    <updated>2007-06-11T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/hex2dec-dec2hex</id>
    <content type="html">&lt;p&gt;For &lt;em&gt;secret reasons&lt;/em&gt; I need to usually convert hex strings to decimal notation. This can be easily done with a scientific calculator, like the one supplied with Windows, but it’s slow and I’m usually in a hurry to convert them :)&lt;/p&gt;

&lt;p&gt;So I took a look at &lt;a href='http://www.greasespot.net/'&gt;GreaseMonkey&lt;/a&gt;, which is an extension for Firefox which allows to modify a web page once rendered with a simple javascript file.&lt;/p&gt;

&lt;p&gt;To install it you’ll first need to have &lt;a href='http://www.greasespot.net/'&gt;GreaseMonkey&lt;/a&gt; installed and activated (a little monkey face on Firefox’s status bar), then click on this link &lt;a href='/files/satkeystringconversor.user.js'&gt;satkeystringconversor.user.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the highlighted source code so you can review it easily. It’s a pretty simple script which traverses the DOM performing regular expression tests on text nodes and converting the matched strings into span elements with an &lt;em&gt;onclick&lt;/em&gt; behaviour.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='c1'&gt;// ==UserScript==&lt;/span&gt;
&lt;span class='c1'&gt;// @name           Sat key string conversor&lt;/span&gt;
&lt;span class='c1'&gt;// @namespace      http://pollinimini.net&lt;/span&gt;
&lt;span class='c1'&gt;// @description    Converts satelite key strings from hex to dec or vice versa&lt;/span&gt;
&lt;span class='c1'&gt;// @include        http://www.satscreen.ws/forum/*&lt;/span&gt;
&lt;span class='c1'&gt;// @include      https://www.blogger.com/*&lt;/span&gt;
&lt;span class='c1'&gt;// @include      http://floresd.blogspot.com/*&lt;/span&gt;
&lt;span class='c1'&gt;// @include      http://galeon.com/tusflores/*&lt;/span&gt;
&lt;span class='c1'&gt;// ==/UserScript==&lt;/span&gt;
&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;HEXDEC&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;node&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

  &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;hex2dec&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;hex&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;dec&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[],&lt;/span&gt;
      &lt;span class='nx'&gt;re&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sr'&gt;/([0-9A-Za-z]{2})\s*/g&lt;/span&gt;&lt;span class='o'&gt;|&amp;gt;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='nx'&gt;conv&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;re&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;exec&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;hex&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nx'&gt;conv&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;parseInt&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt; &lt;span class='mi'&gt;16&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
      &lt;span class='nx'&gt;dec&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;push&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;conv&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='mi'&gt;100&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;conv&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;00&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;conv&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;dec&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;dec2hex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;dec&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;hex&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[],&lt;/span&gt;
      &lt;span class='nx'&gt;re&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sr'&gt;/([0-9]{3})\s*/g&lt;/span&gt;&lt;span class='o'&gt;|&amp;gt;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='nx'&gt;conv&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;re&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;exec&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;dec&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nx'&gt;conv&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;toString&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;16&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;toUpperCase&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
      &lt;span class='nx'&gt;hex&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;push&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;conv&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt; &lt;span class='o'&gt;?&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='nx'&gt;conv&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='nx'&gt;conv&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;hex&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;swapHexDec&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;e&lt;/span&gt; &lt;span class='p'&gt;){&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;e&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;window&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;event&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='nx'&gt;target&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;target&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;srcElement&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='nx'&gt;target&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;srcElement&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeType&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='nx'&gt;target&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;parentNode&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;tmp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;firstChild&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeValue&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;firstChild&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeValue&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;getAttribute&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setAttribute&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;tmp&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;className&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;className&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;dechex&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
      &lt;span class='nx'&gt;target&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;className&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;


  &lt;span class='c1'&gt;// if no node is specified then start processing on the page body&lt;/span&gt;
  &lt;span class='nx'&gt;node&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;node&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;body&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;skipRe&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sr'&gt;/^(script|style|textarea)$/i&lt;/span&gt;&lt;span class='o'&gt;|&amp;gt;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;re&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sr'&gt;/((?:[0-9A-Ha-h]{2}\s*){6,})|((?:[0-9]{3}\s*){6,})/g&lt;/span&gt;&lt;span class='o'&gt;|&amp;gt;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='c1'&gt;// get all nodes from dom&lt;/span&gt;
  &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;nodes&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;node&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;all&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='nx'&gt;node&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;getElementsByTagName&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='c1'&gt;// loop thru all the nodes&lt;/span&gt;
  &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;&amp;lt;&lt;/span&gt;&lt;span class='nx'&gt;nodes&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='c1'&gt;// skip if it has no child nodes, it&amp;#39;s already processed or the tag is not valid&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nx'&gt;nodes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;childNodes&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt;
      &lt;span class='nx'&gt;nodes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;hasAttribute&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt;
      &lt;span class='nx'&gt;skipRe&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;test&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;nodes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;tagName&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;continue&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='c1'&gt;// loop thru all children&lt;/span&gt;
    &lt;span class='nx'&gt;cnode&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;nodes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;childNodes&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
    &lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='c1'&gt;// we just care about text nodes&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeType&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='c1'&gt;// loop thru all regex matches&lt;/span&gt;
        &lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='nx'&gt;re&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;exec&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeValue&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='c1'&gt;// if there is text before the match add it on its own node&lt;/span&gt;
          &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;index&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
            &lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;parentNode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;insertBefore&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
              &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;createTextNode&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeValue&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;index&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nx'&gt;cnode&lt;/span&gt;
            &lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='c1'&gt;// create a new span node for the key string&lt;/span&gt;
          &lt;span class='nx'&gt;span&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;createElement&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;SPAN&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='c1'&gt;// if the first capture parenthesis is found then it&amp;#39;s in hex format&lt;/span&gt;
          &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;className&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
            &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setAttribute&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;hex2dec&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='c1'&gt;// otherwise it is in decimal format&lt;/span&gt;
          &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;className&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;dechex&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
            &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setAttribute&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;hexdec&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;dec2hex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='p'&gt;}&lt;/span&gt;
          &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setAttribute&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Click to swap betwen hex and decimal notations&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;appendChild&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;createTextNode&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='c1'&gt;//span.onclick = swapHexDec;&lt;/span&gt;
          &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addEventListener&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;swapHexDec&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kc'&gt;true&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;parentNode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;insertBefore&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;span&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;cnode&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

          &lt;span class='c1'&gt;// remove the already processed text from the node&lt;/span&gt;
          &lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeValue&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nodeValue&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;substring&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;index&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;m&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='c1'&gt;// reset the regex text pointer&lt;/span&gt;
          &lt;span class='nx'&gt;re&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;lastIndex&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='c1'&gt;// point to next children or null&lt;/span&gt;
      &lt;span class='nx'&gt;cnode&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;cnode&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;nextSibling&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='nb'&gt;window&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addEventListener&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;load&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='nx'&gt;HEXDEC&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;},&lt;/span&gt; &lt;span class='kc'&gt;true&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;addGlobalStyle&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;css&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;head&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nx'&gt;head&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;getElementsByTagName&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;head&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nx'&gt;head&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='nx'&gt;style&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;createElement&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;type&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;text/css&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;innerHTML&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;css&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nx'&gt;head&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;appendChild&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='nx'&gt;addGlobalStyle&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;\&lt;/span&gt;
&lt;span class='s1'&gt;  .hexdec, .dechex { \&lt;/span&gt;
&lt;span class='s1'&gt;    cursor: hand;\&lt;/span&gt;
&lt;span class='s1'&gt;    cursor: pointer !important;\&lt;/span&gt;
&lt;span class='s1'&gt;    border-bottom: 1px dotted #888;\&lt;/span&gt;
&lt;span class='s1'&gt;    padding-left: 32px;\&lt;/span&gt;
&lt;span class='s1'&gt;    background: url(http://pollinimini.net/temp/hex.png) no-repeat left;\&lt;/span&gt;
&lt;span class='s1'&gt;  }\n\&lt;/span&gt;
&lt;span class='s1'&gt;  .dechex {\&lt;/span&gt;
&lt;span class='s1'&gt;    background: url(http://pollinimini.net/temp/dec.png) no-repeat left;\&lt;/span&gt;
&lt;span class='s1'&gt;  }&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;By default the following sites are enabled (you can configure it for whatever sites you need):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;http://www.satscreen.ws/forum/&lt;/li&gt;

&lt;li&gt;http://floresd.blogspot.com/&lt;/li&gt;

&lt;li&gt;http://galeon.com/tusflores/&lt;/li&gt;

&lt;li&gt;https://www.blogger.com/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It uses a neutral blue coloring for the styling which shouldn’t break most web designs. The images are served from my own server, so they aren’t very reliable, don’t be afraid if one day they stop showing :)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=cGNqk_FRd5k:bW9LAYW3BxU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=cGNqk_FRd5k:bW9LAYW3BxU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=cGNqk_FRd5k:bW9LAYW3BxU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=cGNqk_FRd5k:bW9LAYW3BxU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=cGNqk_FRd5k:bW9LAYW3BxU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/cGNqk_FRd5k" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/hex2dec-dec2hex</feedburner:origLink></entry>
  
  <entry>
    <title>Detecting IE with JS conditional comments</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/ScYiA4PHKsQ/detecting-ie-conditional-comments" />
    <updated>2007-04-06T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/detecting-ie-conditional-comments</id>
    <content type="html">&lt;p&gt;I just stumbled upon a short yet excellent post on Dean Edwards blog. It shows how to use IE proprietary javascript conditional comments to detect if we’re running on IE in a secure and very short way.&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;isMSIE&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='cm'&gt;/*@cc_on!@*/&lt;/span&gt;&lt;span class='kc'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Further down in the post’s comments someone named Lucky propose the use of a variant to check against IE 5.5+ and IE7. javascript:&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;ieScript&lt;/span&gt;&lt;span class='cm'&gt;/*@cc_on=@_jscript_version@*/&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;ieScript&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='c1'&gt;// IE&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;ieScript&lt;/span&gt;&lt;span class='o'&gt;&amp;gt;=&lt;/span&gt;&lt;span class='mf'&gt;5.5&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='c1'&gt;// IE 5.5 +&lt;/span&gt;
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;ieScript&lt;/span&gt;&lt;span class='o'&gt;==&lt;/span&gt;&lt;span class='mf'&gt;5.7&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='c1'&gt;// IE 7.0 VistaCopy to clipboard&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Moreover Dean also shows in one of the comments how to check for the rendering path used by IE (quirks VS strict modes)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;ieStrict&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;compatMode&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;CSS1Compat&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;&lt;span class='nx'&gt;Copy&lt;/span&gt; &lt;span class='nx'&gt;to&lt;/span&gt; &lt;span class='nx'&gt;clipboard&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;While is not very wise to abuse the sniffing of browsers vendors it’s also true that sometimes it’s required to split the code path in order to support the incompatibilities among browser vendors and versions.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ScYiA4PHKsQ:MA7GrxKbIRo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ScYiA4PHKsQ:MA7GrxKbIRo:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ScYiA4PHKsQ:MA7GrxKbIRo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=ScYiA4PHKsQ:MA7GrxKbIRo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=ScYiA4PHKsQ:MA7GrxKbIRo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/ScYiA4PHKsQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/detecting-ie-conditional-comments</feedburner:origLink></entry>
  
  <entry>
    <title>Commenting regular expressions in Javascript</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/dXXKc9QFSZ0/commenting-regular-expressions-javascript" />
    <updated>2007-03-20T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/commenting-regular-expressions-javascript</id>
    <content type="html">&lt;p&gt;I’ve been working a lot lately with regular expressions in Javascript. Being a really powerful tool it’s quite easy to get shoot on your own feet if you are not careful.&lt;/p&gt;

&lt;p&gt;After pushing the Javascript built in regular expression engine to its limits I found it lacking some modern features available in most recent versions of regex engines used in many languages like .Net, C++ Boost, Perl, Ruby or PHP. The feature I miss the most is the ability to use &lt;a href='http://www.regular-expressions.info/lookaround.html'&gt;look behind assertions&lt;/a&gt;, with JS just supporting look ahead ones. Another feature I miss are &lt;a href='http://www.regular-expressions.info/named.html'&gt;named groups&lt;/a&gt; and then one very useful new feature is the /x modifier (also known as ignore whitespace) which allows regular expression literals to span over multiple lines, ignoring white space, new lines and embedded comments!&lt;/p&gt;

&lt;p&gt;See the following example regex to match an url:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/\b(https?|ftp):\/\/([-A-Z0-9.]+)(\/[-A-Z0-9+&amp;amp;@#/%=~_|!:,.;]*)?(\?[-A-Z0-9+&amp;amp;@#/%=~_|!:,.;]*)?/i&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Writting it is not difficult but modifiing it or even understanding it becomes an issue. Using the Perl /x modifier it would look like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='n'&gt;m&lt;/span&gt;&lt;span class='o'&gt;/\&lt;/span&gt;&lt;span class='n'&gt;b&lt;/span&gt;                              &lt;span class='c1'&gt;# match at word break&lt;/span&gt;
  &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;https&lt;/span&gt;&lt;span class='p'&gt;?&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;ftp&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;&lt;span class='sr'&gt;//&lt;/span&gt;                 &lt;span class='c1'&gt;# protocol: http, https or ftp&lt;/span&gt;
  &lt;span class='p'&gt;([&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;A&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;Z0&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;9&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;                   &lt;span class='c1'&gt;# domain&lt;/span&gt;
  &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/[-A-Z0-9+&amp;amp;@#/&lt;/span&gt;&lt;span class='nv'&gt;%&lt;/span&gt;&lt;span class='err'&gt;=~&lt;/span&gt;&lt;span class='nv'&gt;_&lt;/span&gt;&lt;span class='o'&gt;|!&lt;/span&gt;&lt;span class='p'&gt;:,&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='p'&gt;;]&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='p'&gt;)?&lt;/span&gt;   &lt;span class='c1'&gt;# file path - optional&lt;/span&gt;
  &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;\&lt;/span&gt;&lt;span class='p'&gt;?[&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;A&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='n'&gt;Z0&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;9&lt;/span&gt;&lt;span class='o'&gt;+&amp;amp;&lt;/span&gt;&lt;span class='nv'&gt;@#&lt;/span&gt;&lt;span class='err'&gt;/%=~&lt;/span&gt;&lt;span class='nv'&gt;_&lt;/span&gt;&lt;span class='o'&gt;|!&lt;/span&gt;&lt;span class='p'&gt;:,&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='p'&gt;;]&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='p'&gt;)?&lt;/span&gt;  &lt;span class='c1'&gt;# query string - optional&lt;/span&gt;
&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;ix&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Much easier to understand, isn’t it? At least I really think so. To imitate this behaviour in Javascript I’ve written this simple function which just concatenates the regular expressions passed as arguments and returns a new one. This allows to break a complex regex into smaller pieces and comment them.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;xRegExp&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;cur&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;re&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;arr&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[];&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;n&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;arguments&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='c1'&gt;// check if the last argument contains the regexp modifiers&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/^[gmi]+$/&lt;/span&gt;&lt;span class='o'&gt;|&amp;gt;&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;test&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;arguments&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;n&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;]))&lt;/span&gt;
        &lt;span class='nx'&gt;n&lt;/span&gt;&lt;span class='o'&gt;--&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='c1'&gt;// go thru all the passed regexes and concatenate them&lt;/span&gt;
    &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;&amp;lt;&lt;/span&gt;&lt;span class='nx'&gt;n&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;typeof&lt;/span&gt; &lt;span class='nx'&gt;arguments&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nx'&gt;arr&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;push&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;arguments&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='c1'&gt;// when we cast a regexp object to a string&lt;/span&gt;
            &lt;span class='c1'&gt;// the / delims and modifiers are included&lt;/span&gt;
            &lt;span class='nx'&gt;cur&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;String&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;arguments&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;
            &lt;span class='nx'&gt;arr&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;push&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;cur&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;substring&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;cur&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;indexOf&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;cur&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;lastIndexOf&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='c1'&gt;// create a new empty regexp&lt;/span&gt;
    &lt;span class='nx'&gt;re&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nb'&gt;RegExp&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
    &lt;span class='c1'&gt;// compile the concatenated regex to speed it up&lt;/span&gt;
    &lt;span class='nx'&gt;re&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;compile&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;arr&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nx'&gt;arguments&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;n&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;re&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Please note that the same thing can be done by concatenating strings manually, however regexes syntax is terse enough without having to double escape all the tokens. That’s why I preffer to write them out in their literal form (between slashes) instead of using quotes.&lt;/p&gt;

&lt;p&gt;Using the given function the above example would look like this. Note that you can use the regexp literal notation or just pass a simple string. The last argument can optionally pass the modifiers for the regular expression.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;re&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;xRegExp&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
    &lt;span class='sr'&gt;/\b/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;                                 &lt;span class='c1'&gt;//match at word break&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;(https?|ftp)://&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;                    &lt;span class='c1'&gt;//protocol: http, https and ftp&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;([-A-Z0-9.]+)&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;                      &lt;span class='c1'&gt;//domain&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;(/[-A-Z0-9+&amp;amp;@#/%=~_|!:,.;]*)?&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;      &lt;span class='c1'&gt;//file path (optional)&lt;/span&gt;
    &lt;span class='sr'&gt;/(\?[-A-Z0-9+&amp;amp;@#/%=~_|!:,.;]*)?/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;     &lt;span class='c1'&gt;//query string (optional)&lt;/span&gt;
    &lt;span class='s1'&gt;&amp;#39;i&amp;#39;&lt;/span&gt;                                   &lt;span class='c1'&gt;//Modifiers: case-insensitive&lt;/span&gt;
&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dXXKc9QFSZ0:MUAEOlpyYII:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dXXKc9QFSZ0:MUAEOlpyYII:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dXXKc9QFSZ0:MUAEOlpyYII:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=dXXKc9QFSZ0:MUAEOlpyYII:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dXXKc9QFSZ0:MUAEOlpyYII:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/dXXKc9QFSZ0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/commenting-regular-expressions-javascript</feedburner:origLink></entry>
  
  <entry>
    <title>Some brief notes on TextAreaPlus</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/P0cyBm2QAOI/some-brief-notes-textareaplus" />
    <updated>2007-03-08T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/some-brief-notes-textareaplus</id>
    <content type="html">&lt;p&gt;Been a quite long time since the last update. I’m a bit ashamed for not keeping the blog updated regularly but I must confess that I’ve been expending my time on other affairs more important to me.&lt;/p&gt;

&lt;p&gt;Anyways, in this weeks I’ve been working again on TextAreaPlus, actually I’ve been busy making a full rewrite of the lexing scanner and optimizing the implementation to the limits of my knowledge. The algorithm used is described in the &lt;a href='http://code.google.com/p/textareaplus/wiki/Lexer'&gt;project wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today I was re-installing the PC at work since it broke havoc yesterday. After finishing the installation of almost all softwares I decided to have a look for a notepad replacement which was more feature packed than &lt;a href='http://www.scintilla.org/SciTE.html'&gt;Scite&lt;/a&gt; and a bit faster than &lt;a href='http://notepad-plus.sourceforge.net/'&gt;Notepad++&lt;/a&gt; to perform some minor editing of config files mainly. In the search I found a couple of new editors which I didn’t knew about but which seem to be gaining momentum. Both seem to be based on a successful Mac text editor called &lt;a href='http://macromates.com/'&gt;TextMate&lt;/a&gt;, which I have heard about from Ruby-on-Rails evangelists but given my allergic reactions to anything mac related lately I didn’t check before. Today, trying those two new editors I got interested in TextMate and I’ve been learning about it in the last hour.&lt;/p&gt;

&lt;p&gt;So long history short, I thought I had invented the sliced bread with my implementation and design ideas for TextAreaPlus but it turns out that Allan Oddgaard, the TextMate developer, already implemented it in a very similar way a couple of years ago. My feelings are a bit conflictive right now, in one way I feel sad because I just reinvented the wheel but in the other I feel reassured to have come up with a solution which turns out to be proved and successful.&lt;/p&gt;

&lt;p&gt;I’ve written a couple hundred words with a couple of links in this post using a lame browser textarea, in moments like this I wish I had already a production ready version of TextAreaPlus. Lets hope I don’t keep wishing for it too long.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P0cyBm2QAOI:JjsUHkmmzwE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P0cyBm2QAOI:JjsUHkmmzwE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P0cyBm2QAOI:JjsUHkmmzwE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=P0cyBm2QAOI:JjsUHkmmzwE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=P0cyBm2QAOI:JjsUHkmmzwE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/P0cyBm2QAOI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/some-brief-notes-textareaplus</feedburner:origLink></entry>
  
  <entry>
    <title>Comprobar un NIF, NIE o CIF</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/8DCI5g3HhW4/comprobar-nif-nie-cif" />
    <updated>2007-02-01T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/comprobar-nif-nie-cif</id>
    <content type="html">&lt;p&gt;Después de postear un simple código para comprobar un NIF, me he mirado un poco más el tema y para mi sorpresa no hay mucha información sobre esto.&lt;/p&gt;

&lt;p&gt;Así que aquí presento una pequeña función para comprobar si el formato de un NIF, NIE o CIF es válido.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;checkIdentidadFiscal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$str&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='c1'&gt;//normalizamos el formato&lt;/span&gt;
    &lt;span class='nv'&gt;$str&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;preg_replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/[^0-9A-Z]/i&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$str&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

    &lt;span class='c1'&gt;// El formato es de un NIF o un NIE&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;preg_match&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/X?[0-9]{8}[A-Z]/i&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='c1'&gt;//para no duplicar código, eliminamos la X en el caso de que sea un NIE&lt;/span&gt;
          &lt;span class='nv'&gt;$str&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;preg_replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/^X/i&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

          &lt;span class='c1'&gt;//calculamos que letra corresponde al número del DNI o NIE&lt;/span&gt;
          &lt;span class='nv'&gt;$stack&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;TRWAGMYFPDXBNJZSQVHLCKE&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
          &lt;span class='nv'&gt;$pos&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;8&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='m'&gt;23&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
          &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;strtoupper&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;8&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$stack&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$pos&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
              &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='c1'&gt;// El formato es el de un CIF&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;preg_match&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/[A-HK-NPQS][0-9]{7}[A-J0-9]/i&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='c1'&gt;//CIF&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='c1'&gt;//sumar los digitos en posiciones pares&lt;/span&gt;
          &lt;span class='nv'&gt;$sum&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
          &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='m'&gt;2&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='o'&gt;&amp;lt;&lt;/span&gt;&lt;span class='nb'&gt;strlen&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='o'&gt;+=&lt;/span&gt;&lt;span class='m'&gt;2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
              &lt;span class='nv'&gt;$sum&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='p'&gt;}&lt;/span&gt;

          &lt;span class='c1'&gt;//Multiplicar los digitos en posiciones impares por 2 y sumar los digitos del resultado&lt;/span&gt;
          &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='o'&gt;&amp;lt;&lt;/span&gt;&lt;span class='nb'&gt;strlen&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='o'&gt;+=&lt;/span&gt;&lt;span class='m'&gt;2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
              &lt;span class='nv'&gt;$t&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$i&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='m'&gt;2&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
              &lt;span class='c1'&gt;//agrega la suma de los digitos del resultado de la multiplicación&lt;/span&gt;
              &lt;span class='nv'&gt;$sum&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$t&lt;/span&gt;&lt;span class='o'&gt;&amp;gt;&lt;/span&gt;&lt;span class='m'&gt;9&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$t&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;9&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;&lt;span class='nv'&gt;$t&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
          &lt;span class='p'&gt;}&lt;/span&gt;

          &lt;span class='c1'&gt;//Restamos el último digito de la suma actual a 10 para obtener el control&lt;/span&gt;
          &lt;span class='nv'&gt;$control&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;10&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$sum&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='m'&gt;10&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

          &lt;span class='c1'&gt;//El control puede ser un número o una letra&lt;/span&gt;
          &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;8&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nv'&gt;$control&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt;
               &lt;span class='nb'&gt;strtoupper&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$str&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;8&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nb'&gt;substr&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;JABCDEFGHI&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$control&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt; &lt;span class='p'&gt;))&lt;/span&gt;
              &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
          &lt;span class='p'&gt;}&lt;/span&gt;

          &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;El algoritmo para comprobar el CIF lo he sacado de &lt;a href='http://es.geocities.com/softcv/codigo/cif.html'&gt;aquí&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8DCI5g3HhW4:CGqXzF3fqTA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8DCI5g3HhW4:CGqXzF3fqTA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8DCI5g3HhW4:CGqXzF3fqTA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=8DCI5g3HhW4:CGqXzF3fqTA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8DCI5g3HhW4:CGqXzF3fqTA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/8DCI5g3HhW4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/comprobar-nif-nie-cif</feedburner:origLink></entry>
  
  <entry>
    <title>Introducing FLV4PHP</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/fu6mqQygUAw/introducing-flv4php" />
    <updated>2006-09-11T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/introducing-flv4php</id>
    <content type="html">&lt;p&gt;This weekend I found some time to work in a new project. In the last post I wrote about streaming video for Flash players, I went thru some different options for that task and one of them was the HTTP progressive download of FLV files.&lt;/p&gt;

&lt;p&gt;There is an interesting idea to make seeking possible when using a simple HTTP download (I think Google Video does just this), it has been already &lt;a href='http://www.flashcomguru.com/index.cfm/2005/11/2/Streaming-flv-video-via-PHP-take-two'&gt;mentioned&lt;/a&gt; in a &lt;a href='http://xprojects.co.uk/modules/news/article.php?storyid=5'&gt;few&lt;/a&gt; &lt;a href='http://flashforever.homeip.net/blog/?p=16'&gt;places&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are some tools already which can inject the needed metadata into an flv file, namely, &lt;a href='http://www.inlet-media.de/flvtool2'&gt;FLVTool2&lt;/a&gt; and &lt;a href='http://www.buraks.com/flvmdi/'&gt;flvmdi&lt;/a&gt;. The &lt;a href='http://ffmpeg.mplayerhq.hu/'&gt;ffmpeg&lt;/a&gt; project can create FLV files and there seem to be already patches to support the creation of metadata entries too.&lt;/p&gt;

&lt;p&gt;Over the years I’ve come to love to develop readers for obscure (not standard neither well documented) file formats, it’s quite a challenge to do it but since the file format spec is not public you have a very good excuse when bugs are found :)&lt;/p&gt;

&lt;p&gt;So I’ve started to work on a system to serve video (and also audio only) files to Flash based players with support for seeking. The idea is to just limit ourselves to use PHP and Flash technologies, no shell scripts or compiled programs, since they are difficult to get running on most shared hosts.&lt;/p&gt;

&lt;p&gt;Right now the FLV analyzing library is finnished and the sample metadata extraction tool can process a 140Mb FLV in just 1.3 seconds on my cheap DreamHost test system.&lt;/p&gt;

&lt;p&gt;So take a look at the project page, right now I’m looking for an Action Script guru to help out with the development of the player. I’ve tried to get my brains around Flash but I haven’t got much success :(&lt;/p&gt;

&lt;p&gt;By the way, all this work will be used for an upcoming project I’m planning. Am I the only one who think that current web photo gallery systems suck?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=fu6mqQygUAw:zS0Ne0-NF5c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=fu6mqQygUAw:zS0Ne0-NF5c:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=fu6mqQygUAw:zS0Ne0-NF5c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=fu6mqQygUAw:zS0Ne0-NF5c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=fu6mqQygUAw:zS0Ne0-NF5c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/fu6mqQygUAw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/introducing-flv4php</feedburner:origLink></entry>
  
  <entry>
    <title>URL argument separator</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/bWoQGfVz_ug/url-argument-separator" />
    <updated>2006-08-11T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/url-argument-separator</id>
    <content type="html">&lt;p&gt;Quite so often a web developer starts thinking what’s wrong with the guys who make the rules of how Internet works. And if we dig a bit in the problem, we can many times see that the ‘non-sense’ is there not because the specs were flawed but because the popular implementations didn’t follow completely the spec.&lt;/p&gt;

&lt;p&gt;The ‘non-sense’ I’ve been thinking about lately is why the hell we use the ampersand &lt;strong&gt;&amp;amp;&lt;/strong&gt; to separate the arguments in a URL. My problem with using the &lt;strong&gt;&amp;amp;&lt;/strong&gt; as separator is that in todays world of XML crazyness, the ampersand must be handled with care. It seems that the specs said that any character could be used after the initial query char mark &lt;strong&gt;?&lt;/strong&gt; but the &lt;strong&gt;#&lt;/strong&gt; which marks the start of the fragment. Actually, in the current specs for URI/URL syntaxis they recommend the semicolon &lt;strong&gt;;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So the decision to choose the ampersand as the defacto standard was taken by the guys who took the lead with the CGI scripts and the dynamic web content generation.&lt;/p&gt;

&lt;p&gt;Since the specs recommend the use of the semicolon I thought “ok, no problem, I’ll just use it from now on” with a grin in my face. If you are thinking the same keep reading because it’s not that easy. My server-side language of choice right now is PHP, so I build up a simple test script to check out if the semicolon worked ok, but it didn’t. After consulting php.net for a bit more of information I found the solution, there are two ini directives which define the argument separators, one for input and the other for output (I guess this last one is used to manage the session id without cookies). &lt;code&gt;arg_separator.input&lt;/code&gt; and &lt;code&gt;arg_separator.output&lt;/code&gt; are the names of the directives. The first one takes a string as argument and every char in that string becomes an argument separator, the second one defines what will PHP use when building URLs as separator.&lt;/p&gt;

&lt;p&gt;The bad news is that the default value is just the ampersand &lt;strong&gt;&amp;amp;&lt;/strong&gt;. The good news is that both directives can be defined per directory, so we can put them in our .htaccess in a shared host. If you control the host just edit the php.ini file. Logically we can’t modify them with ini_set() because the URL is already processed when our script starts execution (see below for a solution to this).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;php_value arg_separator.input &amp;quot;&amp;amp;;&amp;quot;
php_value arg_separator.output &amp;quot;;&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that I left both: the ampersand &lt;strong&gt;&amp;amp;&lt;/strong&gt; and the semicolor &lt;strong&gt;;&lt;/strong&gt; as valid argument separators, I’m far too used to the ampersand and I don’t want to expend my whole life debugging an application just because I forgot that I decided that the semicolon was a better suit :)&lt;/p&gt;

&lt;p&gt;Even if we can’t use the &lt;code&gt;ini_set()&lt;/code&gt; function to modify the PHP behaviour for this, we can still make use of a different argument separator by processing the &lt;code&gt;$_GET&lt;/code&gt; and &lt;code&gt;$_REQUEST&lt;/code&gt; arrays and splitting them by our preffererd argument separator. The following code snippet show do it but please don’t use it in production environments, it’s probably flawed!&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='c1'&gt;// first join the PHP splitted arguments&lt;/span&gt;
&lt;span class='nv'&gt;$get&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;foreach&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$_GET&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='nv'&gt;$k&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='nv'&gt;$v&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='nv'&gt;$get&lt;/span&gt;&lt;span class='o'&gt;.=&lt;/span&gt; &lt;span class='nv'&gt;$k&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;=&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='nv'&gt;$v&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
          &lt;span class='c1'&gt;// remove from the arrays, we&amp;#39;ll add the correct ones later&lt;/span&gt;
          &lt;span class='nb'&gt;unset&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$_GET&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$k&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;
          &lt;span class='nb'&gt;unset&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$_REQUEST&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$k&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='c1'&gt;// split the query string using our desired char&lt;/span&gt;
&lt;span class='nv'&gt;$args&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;split&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$get&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='c1'&gt;// process the query string and rebuild the _GET and _REQUEST array&lt;/span&gt;
&lt;span class='k'&gt;foreach&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$args&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='nv'&gt;$arg&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='c1'&gt;// now separate the key from the value and assign them to the arrays&lt;/span&gt;
          &lt;span class='k'&gt;list&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$k&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nv'&gt;$v&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;explode&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$arg&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
          &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt; &lt;span class='k'&gt;empty&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$k&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
              &lt;span class='nv'&gt;$_GET&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt; &lt;span class='nv'&gt;$k&lt;/span&gt; &lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$v&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
              &lt;span class='nv'&gt;$_REQUEST&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt; &lt;span class='nv'&gt;$k&lt;/span&gt; &lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$v&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
          &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Changing the argument separator does not only help out when working with XML based technologies but also to give your site URLs a geeky look ;)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=bWoQGfVz_ug:-Txur5z_y1Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=bWoQGfVz_ug:-Txur5z_y1Y:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=bWoQGfVz_ug:-Txur5z_y1Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=bWoQGfVz_ug:-Txur5z_y1Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=bWoQGfVz_ug:-Txur5z_y1Y:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/bWoQGfVz_ug" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/url-argument-separator</feedburner:origLink></entry>
  
  <entry>
    <title>Doing Ajax? you'll need transactions!</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/jhZ5D5alXGE/ajax-you-will-need-transactions" />
    <updated>2006-07-10T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/ajax-you-will-need-transactions</id>
    <content type="html">&lt;p&gt;In an embarrassing attempt to bring some more visits to this blog I’ll start to post about buzzwords. After some months of fighting against it I’ve finally understood that there is no point in teaching people that &lt;abbr title='Asynchronous Javascript and XML'&gt;AJAX&lt;/abbr&gt;, Web 2.0 and the like are just silly buzzwords about quite old technologies. So from now on I’ll get into the bandwagon and start using those buzzwords.&lt;/p&gt;

&lt;p&gt;Getting into the stuff that matters, lets start with the basics. As you should already know, the web works on top of the HTTP protocol, which by design is based on a request-response paradigm. It’s a proven design which works like a charm for the typical web, where static pages are loaded from an URL, however the Web is evolving to a new kind of pages. The current trend is to make web pages which act like the typical thin client, where the bulk of the operations and domain logic (model) is performed on the server but the application flow (controller) and display (view) is handled on the client side with the help of JavaScript and &lt;abbr title='Document Object Model'&gt;DOM&lt;/abbr&gt;.&lt;/p&gt;

&lt;p&gt;Looking at the whole picture, you’ll need perspective here, &lt;abbr title='Asynchronous Javascript and XML'&gt;AJAX&lt;/abbr&gt; web pages are Web Service Brokers. This exposes a big problem, since we’re sill using server side software focussed (read optimized) on the traditional web, while the client side is moving to support the thin client paradigm. The main trouble here is the design concept of the web where each page is an atomic unit, so we need to take some considerations when developing ajaxified web pages if we don’t want to hurt performance seriously.&lt;/p&gt;

&lt;p&gt;Most &lt;abbr title='Asynchronous Javascript and XML'&gt;AJAX&lt;/abbr&gt; frameworks expose some simple examples to demonstrate their functionality. They work ok, they do quite cool things, but looking at them a bit closer there are some grey areas. Besides the popular live-search, update on checkbox click or the plain spellchecker, there is a lot more functionality promised by the AJAX hype. Take for example a datagrid widget, like an Excel spreadsheet, there are some complex processes running on the background when working with it. When editting a cell we need to send the new value to the server, check if it worked ok and fetch any other updates on calculated cells which could have been affected by that change. So we have several weak points (mainly by the inherent network unreliability) which would need checks. In the previous example of the datagrid, imagine that the fetch of the affected cells fails, the application state on the client side and on the server side will be different and this is a major concern when working with thin clients.&lt;/p&gt;

&lt;p&gt;To solve this problem we have to use transactions (already popular on the &lt;abbr title='Relational Database Management System'&gt;RDBMS&lt;/abbr&gt; world). Transactions will allow us to emulate the web principle that each page/action is atomic. In the case that something goes wrong we can rollback the changes and our application state will be kept the same on both sides.&lt;/p&gt;

&lt;p&gt;Extending on this idea, we can even optimize the request-response cycle by using an Unit of Work pattern for example. We compose a list of actions and send it when finished to the server instead of sending individual actions. Network latency is always an issue and the asynchronous nature of &lt;abbr title='Asynchronous Javascript and XML'&gt;AJAX&lt;/abbr&gt; is not used too often in practice, when we make a change we expect an inmediate update. By packing the actions in Units of Work we can optimize the client-server interaction and support transactions quite easily.&lt;/p&gt;

&lt;p&gt;Remember that for the tipical &lt;abbr title='Remote Procedure Call'&gt;RPC&lt;/abbr&gt; the web server needs to spawn (or fork) a new process, load the dynamic language interpretter, parse thousends of lines of code, perform a DB connection and do the actual work. Even when having a properly setup backend (opcode cache, fast-cgi), the overhead of a RPC is huge. Packing actions together seems like a great solution for performance problems.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jhZ5D5alXGE:c734idM3CT0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jhZ5D5alXGE:c734idM3CT0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jhZ5D5alXGE:c734idM3CT0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=jhZ5D5alXGE:c734idM3CT0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=jhZ5D5alXGE:c734idM3CT0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/jhZ5D5alXGE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/ajax-you-will-need-transactions</feedburner:origLink></entry>
  
  <entry>
    <title>Como escribir números</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/TxcbJ3qNQtw/como-escribir-numeros" />
    <updated>2006-07-07T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/como-escribir-numeros</id>
    <content type="html">&lt;p&gt;Vaya por delante que el tema no está demasiado estandarizado a nivel internacional. Lo que realmente supone un problema a la hora de interpretar números en un mundo globalizado como el actual.&lt;/p&gt;

&lt;p&gt;Una cosa si que hay en común, según el Sistema Internacional, no se deben separar los millares, en el caso de que haya de hacerse para mejorar su lectura, se hará mediante el uso de un espacio de no rotura, que viene a ser un poco más estrecho que un espacio normal. Este espacio puede introducirse en un editor de textos como Microsoft Word mediante la combinación Ctrl+Shift+Espacio (Ctrl+Espacio para OpenOffice). El código unicode es U+00A0 y en HTML es el conocido &amp;amp;nbsp.&lt;/p&gt;

&lt;p&gt;Para los decimales la cosa es algo más complicada. Hay dos grandes zonas geográficas con dos estilos distintos. La notación anglosajona usa un punto, mientras que en la mayoria del resto de paises se usa la coma.&lt;/p&gt;

&lt;p&gt;Así pues todas las siguientes formas son correctas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;123456.78&lt;/li&gt;

&lt;li&gt;123 456.78&lt;/li&gt;

&lt;li&gt;123456,78&lt;/li&gt;

&lt;li&gt;123 456,78&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A la hora de implementar una aplicación, donde se deben introducir números, lo mejor es soportar todos los formatos en la entrada de información y normalizarlos a la hora de operar con ellos. Si nuestra aplicación solo operará en una región, podemos limitarnos al uso de ese formato específico, aunque hoy en día, y especialmente en apliaciones web, nunca es bueno suponer que solo será usada en una región límitada.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TxcbJ3qNQtw:tZv05CyGmL8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TxcbJ3qNQtw:tZv05CyGmL8:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TxcbJ3qNQtw:tZv05CyGmL8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=TxcbJ3qNQtw:tZv05CyGmL8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=TxcbJ3qNQtw:tZv05CyGmL8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/TxcbJ3qNQtw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/como-escribir-numeros</feedburner:origLink></entry>
  
  <entry>
    <title>Interfacing ODBC from Linux</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/DwetMzhzvvc/interfacing-odbc-linux" />
    <updated>2006-06-02T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/interfacing-odbc-linux</id>
    <content type="html">&lt;p&gt;Our billing software runs on Windows platforms and uses ODBC to store its data. Recently we called the makers of that software since we wanted to extract some Business Intelligence from our records.&lt;/p&gt;

&lt;p&gt;It turned out that they where going to release a new program for that purpose. We asked to evaluate the beta version and to my surprise it just created an Microsoft Excel file with a dynamic table report.&lt;/p&gt;

&lt;p&gt;So I worked on the needed SQL query to extract the records we wanted and exported the data into a CSV to be loaded in an Excel worksheet with a dynamic table report. It worked ok, however the sales and marketting people didn’t want to contact a technician every time they needed the reports to be updated.&lt;/p&gt;

&lt;p&gt;The problem was that our application server is a Debian box and since we didn’t have to much time to expend on this, we looked for the easiest solution. I found &lt;a href='http://odbcsock.sourceforge.net/'&gt;ODBC Socket Server&lt;/a&gt; which seems unmaintained but the last version works ok on our Windows Server 2003 machine. It’s a service which acts as a proxy for ODBC databases in the local machine, so they can be accessed from other machines using a socket connection and a very simple XML grammar. Once everything was in place I wrote a simple PHP program to fetch the needed records (a few thousand rows). To my surprise the available PHP libraries to interact with ODBC Socket Server didn’t perform too well. They stored the full response in memory and then build up an array, since we need a few thousend rows, the amount of memory required was too high for our little Debian system.&lt;/p&gt;

&lt;p&gt;The following code is a pretty simple set of classes to work with ODBC Socket Server. They fetch the data on demand, using a SAX type xml parser to discard the already processed records. It’s not a really thought of or tested solution, however I’m making it public since it’s far better than existing solutions.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='cm'&gt;/*&lt;/span&gt;
&lt;span class='cm'&gt;  The ODBCSock class is an utility object to operate with the ODBC Socket Server&lt;/span&gt;
&lt;span class='cm'&gt;  from http://odbcsock.sourceforge.net&lt;/span&gt;

&lt;span class='cm'&gt;  It&amp;#39;s compatible with ODBC Socket Server&amp;#39;s XML formats 0 and 2. In our tests&lt;/span&gt;
&lt;span class='cm'&gt;  xml format 2 is significally faster than the others.&lt;/span&gt;
&lt;span class='cm'&gt;  Should run on PHP4 and PHP5, however it&amp;#39;s only been tested on PHP5&lt;/span&gt;

&lt;span class='cm'&gt;  This code is copyright (c) 2006 Netxus Foundries&lt;/span&gt;
&lt;span class='cm'&gt;  v1.0 28-May-2006 : Ivan -DrSlump- Montes &amp;lt;imontes@netxus.es&amp;gt;&lt;/span&gt;

&lt;span class='cm'&gt;  This program is free software; you can redistribute it and/or modify&lt;/span&gt;
&lt;span class='cm'&gt;  it under the terms of the GNU General Public License as published by&lt;/span&gt;
&lt;span class='cm'&gt;  the Free Software Foundation; either version 2 of the License, or&lt;/span&gt;
&lt;span class='cm'&gt;  (at your option) any later version.&lt;/span&gt;

&lt;span class='cm'&gt;  This program is distributed in the hope that it will be useful, but&lt;/span&gt;
&lt;span class='cm'&gt;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY&lt;/span&gt;
&lt;span class='cm'&gt;  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License&lt;/span&gt;
&lt;span class='cm'&gt;  for more details.&lt;/span&gt;
&lt;span class='cm'&gt;  You should have received a copy of the GNU General Public License along&lt;/span&gt;
&lt;span class='cm'&gt;  with this program; if not, write to the Free Software Foundation, Inc.,&lt;/span&gt;
&lt;span class='cm'&gt;  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA&lt;/span&gt;
&lt;span class='cm'&gt;*/&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ODBCSock&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$handle&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$server&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$port&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;9628&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$username&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$password&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$database&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;ODBCSock&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$server&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$user&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$passwd&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$database&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nv'&gt;$server&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;explode&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$server&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;count&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$server&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;port&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;array_pop&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$server&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;port&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;9628&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;server&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;implode&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$server&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;handle&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;fsockopen&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;server&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;port&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$errNo&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$errStr&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;30&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;handle&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;username&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$user&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;password&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$passwd&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$database&lt;/span&gt; &lt;span class='o'&gt;!==&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;selectDB&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$database&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;


  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;selectDB&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$database&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;database&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$database&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;


  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&lt;/span&gt; &lt;span class='nf'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$query&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nv'&gt;$pl&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
    &lt;span class='nv'&gt;$pl&lt;/span&gt;&lt;span class='p'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nv'&gt;$pl&lt;/span&gt;&lt;span class='p'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;request&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nv'&gt;$pl&lt;/span&gt;&lt;span class='p'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;connectionstring&amp;gt;DSN=&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='nx'&gt;HTMLSpecialChars&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;database&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;;UID=&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='nx'&gt;HTMLSpecialChars&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;username&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;;PWD=&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='nx'&gt;HTMLSpecialChars&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;password&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;;&amp;lt;/connectionstring&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nv'&gt;$pl&lt;/span&gt;&lt;span class='p'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;sql&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='nx'&gt;HTMLSpecialChars&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$query&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;/sql&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='nv'&gt;$pl&lt;/span&gt;&lt;span class='p'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;/request&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='nb'&gt;fwrite&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;handle&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;implode&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='se'&gt;\r\n&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$pl&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

    &lt;span class='nv'&gt;$rs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;ODBCSock_Result&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$rs&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;sax&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;error&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;FALSE&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$rs&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;


&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ODBCSock_Result&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$rows&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$conn&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$lastRow&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;ODBCSock_Result&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='nv'&gt;$conn&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;conn&lt;/span&gt; &lt;span class='o'&gt;=&amp;amp;&lt;/span&gt; &lt;span class='nv'&gt;$conn&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;sax&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;ODBCSock_SAX&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parser&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;xml_parser_create&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
    &lt;span class='nb'&gt;xml_set_object&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;sax&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nb'&gt;xml_parser_set_option&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;XML_OPTION_CASE_FOLDING&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

    &lt;span class='nb'&gt;xml_set_element_handler&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;startElement&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;endElement&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nb'&gt;xml_set_character_data_handler&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;content&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

    &lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_read&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;sax&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;error&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;sax&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parsing&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;break&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;_eof&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nb'&gt;feof&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;conn&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;handle&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;_read&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='nb'&gt;xml_parse&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;fread&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;conn&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;handle&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;4096&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nb'&gt;feof&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;conn&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;handle&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;addRow&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$row&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
          &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;rows&lt;/span&gt;&lt;span class='p'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$row&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;


  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;fetch&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$row&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$row&lt;/span&gt; &lt;span class='o'&gt;===&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nv'&gt;$row&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;lastRow&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;lastRow&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;lastRow&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$row&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_read&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;

      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;isset&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;rows&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$row&lt;/span&gt;&lt;span class='p'&gt;]))&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;rows&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$row&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;

    &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;_eof&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ODBCSock_SAX&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$error&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$parsing&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$curElement&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$curColumn&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$curColumnIdx&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$curRowIdx&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$rs&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;null&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$row&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='nv'&gt;$labels&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;ODBCSock_SAX&lt;/span&gt;   &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='nv'&gt;$rs&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;rs&lt;/span&gt; &lt;span class='o'&gt;=&amp;amp;&lt;/span&gt; &lt;span class='nv'&gt;$rs&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;startElement&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$attrs&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curElement&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$name&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$name&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;result&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$attrs&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;state&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;success&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;parsing&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
      &lt;span class='k'&gt;else&lt;/span&gt;
        &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;error&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$name&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;row&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;row&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;array&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curColumnIdx&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$name&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;column&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$attrs&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$curRowIdx&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
                &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;labels&lt;/span&gt;&lt;span class='p'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$attrs&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;

        &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curColumn&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$attrs&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curColumn&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;labels&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curColumnIdx&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt;

      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;row&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curColumn&lt;/span&gt; &lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curColumnIdx&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;endElement&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$name&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$name&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;row&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;rs&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;addRow&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;row&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curRowIdx&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;function&lt;/span&gt; &lt;span class='nf'&gt;content&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$parser&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curElement&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;column&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;row&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt; &lt;span class='nv'&gt;$this&lt;/span&gt;&lt;span class='o'&gt;-&amp;gt;&lt;/span&gt;&lt;span class='na'&gt;curColumn&lt;/span&gt; &lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;.=&lt;/span&gt; &lt;span class='nv'&gt;$data&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=DwetMzhzvvc:Tmjdfap-sxM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=DwetMzhzvvc:Tmjdfap-sxM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=DwetMzhzvvc:Tmjdfap-sxM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=DwetMzhzvvc:Tmjdfap-sxM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=DwetMzhzvvc:Tmjdfap-sxM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/DwetMzhzvvc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/interfacing-odbc-linux</feedburner:origLink></entry>
  
  <entry>
    <title>The Binary Search algorithm</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/JFVbN9aawY8/binary-search-algorithm" />
    <updated>2006-05-23T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/binary-search-algorithm</id>
    <content type="html">&lt;p&gt;Long time since I last wrote here so I’ll take the opportunity to introduce (just joking) the Binary Search algorithm.&lt;/p&gt;

&lt;p&gt;I was looking for a safe way to find the line of text where a user clicks the mouse. I needed this for the TextArea+ editor. Fortunately Mozilla supports the DOM3’s compareDocumentPosition() function, so I took advantatge of it. Since I’m using a UL with an LI child element for each line of text, I can say that UL.childNodes is an ordered array, which fits perfectly for the Binary Search algorithm.&lt;/p&gt;

&lt;p&gt;The algorithm is really simple (I’m sure most of you have used it before), we just need to find the middle point between two points and compare its value with the one we’re looking for. We do this recursively until we either find the value or the right point becomes smaller than the left one, which means that the value is just not there.&lt;/p&gt;

&lt;p&gt;Here comes a really simple example of this algorithm (without using recursive calls)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;left&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;right&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;100&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;left&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;=&lt;/span&gt; &lt;span class='nx'&gt;right&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

    &lt;span class='nx'&gt;middle&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;floor&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;right&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nx'&gt;left&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;left&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;haystack&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;mid&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='nx'&gt;needle&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nx'&gt;alert&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Found!&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='k'&gt;break&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;needle&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='nx'&gt;haystack&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;middle&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='nx'&gt;right&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;middle&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
        &lt;span class='nx'&gt;left&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;middle&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The Binary Search algorithm performs at O(log n) time, but for TextArea+ I use a number of further optimizations. Since it’s likely that the user will click closely to where the cursor currently is, I just check the N precedding and following lines before. If this fails I check the current viewport and if still not found, then just do a full search. And this is just for the Mozilla code path! hell, how I hate cross-browser coding!&lt;/p&gt;

&lt;p&gt;This post is meant to remind us how important is to learn already known and proved algorithms and that even when having a good algorithm, there is always room to optimize by taking advantge of our specific problem.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=JFVbN9aawY8:Wc6ldrx9BU0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=JFVbN9aawY8:Wc6ldrx9BU0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=JFVbN9aawY8:Wc6ldrx9BU0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=JFVbN9aawY8:Wc6ldrx9BU0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=JFVbN9aawY8:Wc6ldrx9BU0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/JFVbN9aawY8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/binary-search-algorithm</feedburner:origLink></entry>
  
  <entry>
    <title>Programmatic reflection effect</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/MKRB3q-Kxcg/programmatic-reflection-effect" />
    <updated>2006-04-28T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/programmatic-reflection-effect</id>
    <content type="html">&lt;p&gt;Today &lt;a href='http://franciscovargas.net/'&gt;Haripako&lt;/a&gt; pointed us to &lt;a href='http://mir.aculo.us/'&gt;Thomas Fuchs&lt;/a&gt; (of &lt;a href='http://script.aculo.us/'&gt;script.aculo.us&lt;/a&gt; fame) &lt;a href='http://mir.aculo.us/articles/2006/04/27/like-reflections-try-the-reflector'&gt;DHTML image reflection effect&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It uses 1px tall divs with an adjusted top offset for the containing image and the opacity property to perform it. Well, you just need to know some basic arithmetics to create this kind of effects, but I guess that if people find this kind of stuff so cool is just because most of them only do maths to check their wages :)&lt;/p&gt;

&lt;p&gt;So here is some PHP to perform the same effect on the server side&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='cp'&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class='nv'&gt;$file&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;test.png&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;

&lt;span class='c1'&gt;// Configuration params&lt;/span&gt;
&lt;span class='nv'&gt;$mirrorSize&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;1.35&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;   &lt;span class='cm'&gt;/* 1 .. 2 */&lt;/span&gt;
&lt;span class='nv'&gt;$startAlpha&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;80&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;     &lt;span class='cm'&gt;/* 0 .. 127 */&lt;/span&gt;

&lt;span class='c1'&gt;// Adjust params to supported limits&lt;/span&gt;
&lt;span class='nv'&gt;$mirrorSize&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;max&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;min&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$mirrorSize&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nv'&gt;$startAlpha&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;max&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;min&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$startAlpha&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;127&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Load the source file&lt;/span&gt;
&lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;ImageCreateFromPng&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$file&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Create the reflect portion&lt;/span&gt;
&lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;ImageCreateTrueColor&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;ImagesX&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nb'&gt;floor&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$mirrorSize&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;ImageAlphaBlending&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$imgRfl&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;ImageFill&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;ImageColorAllocate&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;255&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='m'&gt;255&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='m'&gt;255&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='nv'&gt;$offset&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// In this loop we flip the source image and apply a fade out&lt;/span&gt;
&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nv'&gt;$y&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt; &lt;span class='nv'&gt;$y&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nx'&gt;ImageCopy&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nv'&gt;$y&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nv'&gt;$y&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;ImagesX&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='m'&gt;1&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nv'&gt;$alpha&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;floor&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$y&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='m'&gt;127&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nv'&gt;$startAlpha&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nv'&gt;$color&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;ImageColorAllocateAlpha&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;255&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='m'&gt;255&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='m'&gt;255&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;127&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nv'&gt;$startAlpha&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nv'&gt;$alpha&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='nx'&gt;ImageFilledRectangle&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$y&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;ImagesX&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$y&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='m'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$color&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;

&lt;span class='c1'&gt;// Create the image buffer which will be outputted&lt;/span&gt;
&lt;span class='nv'&gt;$imgDst&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;ImageCreateTrueColor&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;ImagesX&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='nv'&gt;$mirrorSize&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;ImageAlphaBlending&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;$imgDst&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;false&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Paste into the output buffer the original image and the reflect portion&lt;/span&gt;
&lt;span class='nx'&gt;ImageCopy&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgDst&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;ImagesX&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;ImageCopy&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgDst&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='m'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;ImagesX&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='nx'&gt;ImagesY&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='nx'&gt;ImageDestroy&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgSrc&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;ImageDestroy&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgRfl&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='c1'&gt;// Output the image&lt;/span&gt;
&lt;span class='nb'&gt;header&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Content-type: image/png&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;ImageSaveAlpha&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgDst&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;true&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;ImagePng&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgDst&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;

&lt;span class='nx'&gt;ImageDestroy&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nv'&gt;$imgDst&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I’ve tried to keep it very simple, so it’ll only work with PNG files. Moreover it’s hardcoded for white backgrounds, althought it can be easily changed.&lt;/p&gt;

&lt;p&gt;If you use this be sure to cache the result, since the cpu cycles to process images is quite high.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=MKRB3q-Kxcg:rDHigaiNLWs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=MKRB3q-Kxcg:rDHigaiNLWs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=MKRB3q-Kxcg:rDHigaiNLWs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=MKRB3q-Kxcg:rDHigaiNLWs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=MKRB3q-Kxcg:rDHigaiNLWs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/MKRB3q-Kxcg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/programmatic-reflection-effect</feedburner:origLink></entry>
  
  <entry>
    <title>Implementing a line based code editor</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/tcWUggwDTWA/implementing-line-based-code-editor" />
    <updated>2006-04-06T00:00:00+02:00</updated>
    <id>http://pollinimini.net/blog/implementing-line-based-code-editor</id>
    <content type="html">&lt;p&gt;To my surprise I couldn’t find much info on the net about implementing text editors. So I had to figure it out on my own, however as often happens, while implementing it I found some info when looking for related stuff.&lt;/p&gt;

&lt;p&gt;There seems to be two common ways to implement text editors, those which are line-based and those which are block-based. I started with the block-based approach, dividing the text buffer in tokens and storing the position and color attributes in each block. Soon I found that this approach gets pretty complex quite fast. So I turned the code into a line-based editor. It’s almost like the block based with the main difference that it makes an intermediate division based on lines of text. This allows to simplify the code at the expense of a bit of overhead.&lt;/p&gt;

&lt;p&gt;For each line of text we need to store the actual text (or the coordinates to fetch it from a buffer), the offset relative to the start of the text, the parser state at the start of the line and block definitions for that line. Since we have broken down the text in lines, for each block we just need to store the offset relative to the start of line which contains it, the length of the block and the style of it. The following figure illustrates the whole concept.&lt;/p&gt;

&lt;p&gt;&lt;img src='/resources/linebased.png' alt='Figure' /&gt;&lt;/p&gt;

&lt;p&gt;To make all this work we just need a function which parses a single line of text. This function would take as arguments a string with the line of text and the parser context at the start of that line. It will return the blocks found and the parser context at the end of the line.&lt;/p&gt;

&lt;p&gt;The code would roughly look like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nx'&gt;txtLines&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;split&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;text&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;lines&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nb'&gt;Array&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='nx'&gt;context&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;Context&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;span class='nx'&gt;offset&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='nx'&gt;count&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;txtLines&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt; &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
   &lt;span class='nx'&gt;lines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;source&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;txtLines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;];&lt;/span&gt;
   &lt;span class='nx'&gt;lines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;offset&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
   &lt;span class='nx'&gt;lines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;state&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;state&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
   &lt;span class='nx'&gt;lines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;blocks&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;parseLine&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;txtLines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt; &lt;span class='nx'&gt;context&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
   &lt;span class='nx'&gt;offset&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='nx'&gt;strlen&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;txtLines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The advantatge of the line based approach is that it’s very easy to reparse the text to display any changes on the syntax highlighting. To do so we just need to parse each line from the modified one to the end until the parser context matches&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nx'&gt;context&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;line&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;context&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
   &lt;span class='nx'&gt;lines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;blocks&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;parseLine&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;lines&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;text&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;context&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
   &lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='o'&gt;++&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='k'&gt;while&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt; &lt;span class='nx'&gt;context&lt;/span&gt; &lt;span class='o'&gt;!=&lt;/span&gt; &lt;span class='nx'&gt;line&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;i&lt;/span&gt;&lt;span class='p'&gt;].&lt;/span&gt;&lt;span class='nx'&gt;context&lt;/span&gt; &lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Most of the time, buffer changes will only affect a line and most lines will only be a few chars long, so we have a really optimized solution with only a few lines of code.&lt;/p&gt;

&lt;p&gt;In overall, writing a fast text editor is quite simple if we only optimize for the common cases. In fact, I’m having more problems optimizing the display routines than the buffer updating ones.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=tcWUggwDTWA:9nU0xvVXL7Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=tcWUggwDTWA:9nU0xvVXL7Y:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=tcWUggwDTWA:9nU0xvVXL7Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=tcWUggwDTWA:9nU0xvVXL7Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=tcWUggwDTWA:9nU0xvVXL7Y:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/tcWUggwDTWA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/implementing-line-based-code-editor</feedburner:origLink></entry>
  
  <entry>
    <title>Browser based syntax highlighting code editor (part ||)</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/dmATD3Ay3b8/browser-based-syntax-highlighting-code-editor-2" />
    <updated>2006-03-26T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/browser-based-syntax-highlighting-code-editor-2</id>
    <content type="html">&lt;p&gt;In a previous post I was moaning about the lack of a proper browser based (dhtml powered) syntax highlighting code editor.&lt;/p&gt;

&lt;p&gt;I took the aproach descrived in that post of using a translucent textarea over the syntax highlighted code to achieve the result with the minimum of effort. Well, it hast turned out that it won’t work as fast as spected. The performance is horrible, at least in Firefox, so I’ve abandoned this aproach.&lt;/p&gt;

&lt;p&gt;However, as I already have the code to highlight the code in real-time, I’m trying to implement the code editor following a more natural aproximation, which is to capture the keyboard input and process it. To speed up development time I’m focussing just in Firefox, but I guess it’ll be portable to IE, Opera 8.x and Safari quite easily.&lt;/p&gt;

&lt;p&gt;To capture the input from the user we need to handle some events: onFocus, onBlur and onKeypress. Unfortunatly Gecko only allows onKeypress events on input and textarea fields (IE doesn’t have this limitation). To sort this problem out we just need to create a non-visible text input field (style.display: none) which receives the focus when the element containing the editor does. This way we can trick Gecko and make use of onKeypress evens (in IE this won’t work, since it doesn’t fire events on non-visible elements). The drawback with this is that the selection, if any, is lost when changing the focus to the input field, however it can be easily solved by recreating the selection range after switching focus.&lt;/p&gt;

&lt;p&gt;The syntax highlighting algorithm uses regular expressions, since they should be much faster than implementing a traditional tokenizer/lexer in javascript. This means that, at least for now, the highlighting can’t be nested (“Hello $userName” is rendered in one color, as string, without applying another style to the variable $userName). Basicly, what the code does is create an internal structure divided in lines which in turn have N blocks. Each block defines an offset from the start of the line and a style (normal, comment, string …)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='c1'&gt;// comment&lt;/span&gt;
&lt;span class='nx'&gt;$text&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;string test&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;becomes&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='p'&gt;[&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='nx'&gt;blocks&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;
            &lt;span class='p'&gt;{&lt;/span&gt;
                    &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                    &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;comment&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='p'&gt;]&lt;/span&gt;
    &lt;span class='p'&gt;},&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='nx'&gt;blocks&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;
            &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;       &lt;span class='c1'&gt;// $text&lt;/span&gt;
                &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;var&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='p'&gt;},&lt;/span&gt;
            &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;       &lt;span class='c1'&gt;//  =&lt;/span&gt;
                &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='p'&gt;},&lt;/span&gt;
            &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;8&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;       &lt;span class='c1'&gt;// &amp;quot;string text&amp;quot;&lt;/span&gt;
                &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='p'&gt;},&lt;/span&gt;
            &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='nx'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;22&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;      &lt;span class='c1'&gt;// ;&lt;/span&gt;
                &lt;span class='nx'&gt;style&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='p'&gt;]&lt;/span&gt;
    &lt;span class='p'&gt;},&lt;/span&gt;
&lt;span class='p'&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This data structure is specially suited to parse source code, where most tokens can’t span over multiple lines. However, it’ll be very limited for languages like XML until we don’t support a stack based tokenizer (just a simple finite state machine).&lt;/p&gt;

&lt;p&gt;That’s it for now, next installment will probably focus on how to handle the keyboard events :)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dmATD3Ay3b8:RjL-mtlsPGg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dmATD3Ay3b8:RjL-mtlsPGg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dmATD3Ay3b8:RjL-mtlsPGg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=dmATD3Ay3b8:RjL-mtlsPGg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=dmATD3Ay3b8:RjL-mtlsPGg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/dmATD3Ay3b8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/browser-based-syntax-highlighting-code-editor-2</feedburner:origLink></entry>
  
  <entry>
    <title>document.createElement('INPUT')</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/iF17bspMEjY/document-createelement-input" />
    <updated>2006-03-22T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/document-createelement-input</id>
    <content type="html">&lt;p&gt;Just a quick post about yet another Internet Explorer glitch&lt;/p&gt;

&lt;p&gt;When you want to add a new input element to a page, you must define the type attribute before including the new element in the document tree.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;inp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;createElement&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;INPUT&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;inp&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setAttribute&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;checkbox&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;body&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;appendChild&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;inp&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I was going crazy because I had the 2nd and 3rd lines swapped, which makes Internet Explorer display the input element as type text and gives an exception when trying to change the type.&lt;/p&gt;

&lt;p&gt;In my coding style, even if it’s not the more efficient one, I try to append the new elements just after creating them so I don’t forget to do it.&lt;/p&gt;

&lt;p&gt;Ideally, to optimize the execution speed, we should always add the element when it’s completely defined, to avoid browser redraws. Even if we need to add a bunch of elements, it’s better to create them in a document fragment, outside the document tree, and when we are done just insert the whole fragment.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=iF17bspMEjY:SWLLxQwjZOY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=iF17bspMEjY:SWLLxQwjZOY:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=iF17bspMEjY:SWLLxQwjZOY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=iF17bspMEjY:SWLLxQwjZOY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=iF17bspMEjY:SWLLxQwjZOY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/iF17bspMEjY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/document-createelement-input</feedburner:origLink></entry>
  
  <entry>
    <title>My take on a flexible persmission system</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/8bGD_P-gSFQ/my-take-on-flexible-permission-system" />
    <updated>2006-03-17T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/my-take-on-flexible-permission-system</id>
    <content type="html">&lt;p&gt;Since I started programming using data sources and more specially web apps, I’ve always been looking for a flexible enough permission system to use in my projects. No matter how complicated the permission system implemented was that the client would ask for a given combination which isn’t supported by it &amp;gt;:(&lt;/p&gt;

&lt;p&gt;Just recently a fellow developer told me about OpenLdap permissions system. I’ve been using a central repository (I call it registry) for all entities in my database schemas, this allows me to do a very light-weight pseudo object oriented data layer on top of a relational database like MySQL. This system is a bit similar to an LDAP datastore, after all it’s nothing more than a hierarchical object database. However, studying more in detail OpenLdap’s permission system I had all of the sudden the following idea.&lt;/p&gt;

&lt;p&gt;Permission checks must be flexible and very fast, say you have a database with 10 thousend contacts which can be readed by the users in the same group as the owner and edited by the administration group and by the owner. Obviously you can’t waste 2 seconds just to query the database for the contacts an user is able to see in a listing. So I tried to simplify the whole concept, starting by what is a permission, when applied to an object/entity/resource a permission can be None, Read, Write or Delete. Things like Print or Export are in fact the Read permission, only with a different presentation layer. Since it’s only four possible values we can represent it with a simple integer like 0, 1, 2 and 4 respectively. So now, in this system, you have a registry with all the entities and another table with all the users. The only missing piece is to relate the entities with the users, for that the simplest thing to do (and the more flexible) is just to create a relation table which has a composite primary key of the entity id and the user id, as an attribute we put the access level we described as an int above. Now, we said we had 10.000 contacts or entities for this matter, and say we have 100 users, the resulting relation table could be upto 10.000×100 = 1 million rows! That is quite a lot of rows, even if it’s quite doubtfull that we will use the maximum of rows, it’s clear that this system has a drawback and this is that it won’t scale well with a huge number of users. I can live with it actually, at least it serves my purposes. If someone needs an application for some hundreds of users he may probably spend some bucks on a powerfull server :)&lt;/p&gt;

&lt;p&gt;So now we have a system which allows for really flexible permissions but which only requires a simple table join to check them. Obviously it’s not operative right now, since we need a way to build the ACL table. In this task is where the OpenLdap method comes in handy. Basicly it allows to create rules based on the entity attributes (aka entity fields), so we can create a simple parser for this rules and populate the ACL table accordingly. Take the following example acl, it defines that all users can read any entity and the owner can write to it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; access to *
       by self  write
       by users read
       by *     none&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’m not saying we need to implement OpenLdap’s syntax, it probably doesn’t fit too well a relational model, however it helps to ilustrate how we can achieve a very complex permissions system. One thing to note is that when the permission definition is modified, the whole ACL table needs to be recalculated. However, when we add a new entry we just need to calculate that new entry, so the overall performance is quite good.&lt;/p&gt;

&lt;p&gt;In my opinion what this method offers compared to other commonly used permission systems in web applications is that it calculates the permission when creating/updating objects (or modifying the permission definitions) instead of performing complex (many times also slower) calculations when selecting data, which is most cases is the most frequent operation.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8bGD_P-gSFQ:BiwUjC7Urjg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8bGD_P-gSFQ:BiwUjC7Urjg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8bGD_P-gSFQ:BiwUjC7Urjg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=8bGD_P-gSFQ:BiwUjC7Urjg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=8bGD_P-gSFQ:BiwUjC7Urjg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/8bGD_P-gSFQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/my-take-on-flexible-permission-system</feedburner:origLink></entry>
  
  <entry>
    <title>El uso de RAM del Exchange Store.EXE</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/3x-YER32wwk/ram-del-exchange-store-exe" />
    <updated>2006-03-16T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/ram-del-exchange-store-exe</id>
    <content type="html">&lt;p&gt;Ya me he encontrado en varios servidores que el proceso Store.EXE del Microsoft Exchange usa cantidades desmesuradas de memoria.&lt;/p&gt;

&lt;p&gt;En realidad esto lejos de ser un problema, es una característica del Exchange desde la versión 2000 creo. Para explicar porque hace esto de chupar memoria como si fuera un vampiro biteriano, primero hay que explicar como funciona el sistema de almacenamiento del Exchange.&lt;/p&gt;

&lt;p&gt;Cuando recive un nuevo correo/contacto/fichero, vamos lo que sea que tenga que ser almacenado en los buzones, lo primero que hace es escribirlo en un fichero de logeado. De esta forma no tiene que estar esperando a que la base de datos este disponible para meter el mensaje, así que simplemente guarda la nueva petición en un fichero de log y vuelve a la espera de nuevas entradas. Por otro lado, un subproceso se encarga de ir procesando esos logs y va introduciendo las nuevas entidades en la base de datos. Como no tiene prisa por volver a escuchar nuevas peticiones, puede introducir los elementos en la base de datos de una forma adecuada. Adicionalmente, este sistema tiene la ventaja de que si se colgara el servidor (se va la luz, peta el exchange, vuelcas el café en el teclado…), no se perdería nada, ya que los datos se han guardado en los fichero de log, y aunque la base de datos quede corrupta por una operación no finalizada, Exchange puede restaurarla a un estado optimo haciendo uso de esos mismos logs.&lt;/p&gt;

&lt;p&gt;Todo este rollo, nos viene al pelo para explicar el porque del alto consumo de RAM del proceso Store.EXE. Lo que hace es guardar los datos en el log y al mismo tiempo mantenerlos en memoria, a modo de cache, así que usará toda la memoria que tengamos disponible para crear un cache lo más eficiente posible. Por supuesto, los ingenieros de Microsoft no son tan tontos como para pensar que por ser quienes son tienen derecho a ‘secuestrar’ toda la RAM de un servidor. Lo que hace este proceso es usar una técnica llamada Dynamic Buffer Allocation, la cual va usando toda la memoria que quiere pero vigila el uso de la memoria virtual (cache de disco), si detecta que empieza a usarse la memoria virtual, el proceso comenzará a reducir su cache para dejar RAM libre a otras aplicaciones.&lt;/p&gt;

&lt;p&gt;Como nota adicional, en mi busqueda de información he leido que para calcular la RAM necesaria para un Exchange (version 2003) se puede usar esta formula: 256Mb + 1Mb * Buzón Logicamente cuanto más RAM tenga mejor rendimiento, debido al uso del mencionado cache. Por cierto, para servidores con más de 1Gb se recomienda usar las opciones /3GB /USERVA=3030 en el boot.ini, y cambiar el valor del registro HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\HeapDeCommitFreeBlockThreshold a 0×00040000, para evitar la fragmentación de la memoria.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=3x-YER32wwk:paIuDsqaWSY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=3x-YER32wwk:paIuDsqaWSY:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=3x-YER32wwk:paIuDsqaWSY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=3x-YER32wwk:paIuDsqaWSY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=3x-YER32wwk:paIuDsqaWSY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/3x-YER32wwk" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/ram-del-exchange-store-exe</feedburner:origLink></entry>
  
  <entry>
    <title>Browser based syntax highlighting code editor</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/Qk4rTTfA_Yc/browser-based-syntax-highlighting-code-editor" />
    <updated>2006-02-21T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/browser-based-syntax-highlighting-code-editor</id>
    <content type="html">&lt;p&gt;I’ve been looking for a working source code / plain text editor which can be run on a browser. There are dozens of WYSIWYG html editors out there (see &lt;a href='http://www.geniisoft.com/showcase.nsf/WebEditors'&gt;here&lt;/a&gt; for a comprehensive list). However, for pure source code or just plain text I just found two options: &lt;a href='http://helene.muze.nl/'&gt;Helene&lt;/a&gt; and &lt;a href='http://aboutedit.com/'&gt;About:Edit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first one, Helene, is open source software but it’s not ready for production use. The other one, About:Edit, looks really cool but it’s commercial which is good but I can’t afford to buy a license, so it’s not a realistic option in my case.&lt;/p&gt;

&lt;p&gt;Thinking a bit about the main problem of that kind of editors, it seems to be that browsers don’t support natively the editing of hightlighting code, even if it can be emulated with the WYSIWYG editors it doesn’t feel like it’ll be very efficient and/or clean. So I took another approach, which is a bit of a hack but I think that can solve my needs pretty well. The hack is just to use modern browsers absolute positioning and opacity settings. We just place a div below a textarea, with the same sizes, then put the opacity of the textarea to 30% and we set the text color to white. Then we just need to update the underlying div with the changes in the textarea, all the text editing, cut&amp;amp;paste, selection &amp;#8230; is handled natively by the browser but we can style the contents (like syntax highlighting) in the div.&lt;/p&gt;

&lt;p&gt;It doesn’t look perfect, since the half transparent textarea makes the colors look too soft but the speed is great and it’s really easy to implement.&lt;/p&gt;

&lt;p&gt;Expect a simple demo sometime next week, I’m a bit too busy right now too expend my time on this kind of experiments :(&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Qk4rTTfA_Yc:K6_THjZVWNw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Qk4rTTfA_Yc:K6_THjZVWNw:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Qk4rTTfA_Yc:K6_THjZVWNw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=Qk4rTTfA_Yc:K6_THjZVWNw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Qk4rTTfA_Yc:K6_THjZVWNw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/Qk4rTTfA_Yc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/browser-based-syntax-highlighting-code-editor</feedburner:origLink></entry>
  
  <entry>
    <title>Goodbye MacroCSS, long live CSSing</title>
    <link href="http://feedproxy.google.com/~r/drslump/~3/Q7E2hpcYgzY/goodbye-macrocss-long-live-cssing" />
    <updated>2006-02-13T00:00:00+01:00</updated>
    <id>http://pollinimini.net/blog/goodbye-macrocss-long-live-cssing</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve just spend an hour chatting with Daniel Mota (aka &lt;a href='http://icebeat.bitacoras.com/'&gt;IceBeat&lt;/a&gt;) about his project &lt;a href='http://cssing.sourceforge.net/'&gt;CSSing&lt;/a&gt;. I’ve been following its developement for some months now, in fact I started my own version, MacroCSS, since he didn’t have released the source code at that time.&lt;/p&gt;

&lt;p&gt;I didn’t have the time to continue the development of MacroCSS, I did manage though to implement a SAC based parser for CSS which turned out to be quite powerful. IceBeat was searching with a &lt;a href='http://icebeat.bitacoras.com/archivo/177/parseo-css'&gt;post&lt;/a&gt; in his blog for a replacement for his regular expression based parser. I pointed him to MacroCSS and he was quite impressed with it.&lt;/p&gt;

&lt;p&gt;After chatting with him I’m quite happy, not just because he liked my parser but because we almost share the same vision for this project. Since as I said, I don’t have the time to continue the development of MacroCSS on my own, I’m deprecating it and I’ll focus on helping IceBeat with CSSing in what I can.&lt;/p&gt;

&lt;p&gt;I really think this project could be a real hit for the web development comunity, it fits really well with other ‘web 2.0’ (hell, how much I hate that term) technologies like ajax (I hate this one even more). So if anyone is reading this and wants to help out, he/she will be more than welcome.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Q7E2hpcYgzY:pnvwEjn-kqE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Q7E2hpcYgzY:pnvwEjn-kqE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Q7E2hpcYgzY:pnvwEjn-kqE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?i=Q7E2hpcYgzY:pnvwEjn-kqE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/drslump?a=Q7E2hpcYgzY:pnvwEjn-kqE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/drslump?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/drslump/~4/Q7E2hpcYgzY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://pollinimini.net/blog/goodbye-macrocss-long-live-cssing</feedburner:origLink></entry>
  
</feed>

