<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Web Dev Web Log</title> <atom:link href="http://www.drcoen.com/feed/" rel="self" type="application/rss+xml" /><link>http://www.drcoen.com</link> <description>or bdev blog for short</description> <lastBuildDate>Sat, 12 May 2012 17:11:18 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.1.4</generator> <item><title>window.onload firing too early in IE</title><link>http://www.drcoen.com/2012/05/window-onload-firing-too-early-in-ie/</link> <comments>http://www.drcoen.com/2012/05/window-onload-firing-too-early-in-ie/#comments</comments> <pubDate>Sat, 12 May 2012 17:06:01 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Bug solution]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[ie]]></category> <category><![CDATA[internet-explorer]]></category> <category><![CDATA[javascript]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=94</guid> <description><![CDATA[The Problem Where I work, our tool supports 6 different languages, where translations are contained in various sets of language files. One of these sets consists of the translations stored in Javascript files as JSON blocks, something like translations.en.js containing a structure 1234Translations = &#123; &#160; &#160; helloWorld: &#34;Hello world&#34;, &#160; &#160; // ... etc. [...]]]></description> <content:encoded><![CDATA[<h2>The Problem</h2><p>Where I work, our tool supports 6 different languages, where translations are contained in various sets of language files. One of these sets consists of the translations stored in Javascript files as JSON blocks<span
id="more-94"></span>, something like <code>translations.en.js</code> containing a structure</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Translations <span
style="color: #339933;">=</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; helloWorld<span
style="color: #339933;">:</span> <span
style="color: #3366CC;">&quot;Hello world&quot;</span><span
style="color: #339933;">,</span><br
/> &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// ... etc.</span><br
/> <span
style="color: #009900;">&#125;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>Translation works by looking for spans with an attribute <code>data-lang</code>, which in the above example would be <code>&lt;span data-lang="helloWord"&gt;&lt;/span&gt;</code>, and swaps in the relevant string to make it <code>&lt;span data-lang="helloWord"&gt;Hello world&lt;/span&gt;</code>.</p><p>In this particular instance, the current language was only obtainable from the client, so the page would have to load while <code>var current_lang</code> was initialised. Once I had the current language, I was looking to load the file on the fly, kind of like the way you add Google Analytics code to your page, something like (in <code>&lt;script&gt;</code> tags in the document head):</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #006600; font-style: italic;">//load the language file</span><br
/> script <span
style="color: #339933;">=</span> document.<span
style="color: #660066;">createElement</span><span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'script'</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> script.<span
style="color: #660066;">type</span><span
style="color: #339933;">=</span><span
style="color: #3366CC;">&quot;text/javascript&quot;</span><span
style="color: #339933;">;</span><br
/> script.<span
style="color: #660066;">src</span> <span
style="color: #339933;">=</span> <span
style="color: #3366CC;">&quot;../lang/translations.&quot;</span> <span
style="color: #339933;">+</span> current_lang <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">&quot;.js&quot;</span><span
style="color: #339933;">;</span><br
/> document.<span
style="color: #660066;">getElementsByTagName</span><span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">&quot;head&quot;</span><span
style="color: #009900;">&#41;</span><span
style="color: #009900;">&#91;</span><span
style="color: #CC0000;">0</span><span
style="color: #009900;">&#93;</span>.<span
style="color: #660066;">appendChild</span><span
style="color: #009900;">&#40;</span>script<span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>Further down the document, I had my <code>window.onload</code> function which swaps in the translations by looking up the <code>Translations</code> object.</p><p>As usual, this worked fine in all browsers, except Internet Explorer. You would expect that a browser&#8217;s <code>window.onload</code> event would only fire once all files have been loaded and the document has &#8216;settled down&#8217;. However, with IE, <code>window.onload</code> was firing before the language file had loaded and thus I was getting an &#8220;unknown variable: &#8216;Translations&#8217;&#8221; kind of error.</p><h2>The Solution</h2><p>In order to get around this, I created a global variable called <code>translationsLoaded</code> (set to <code>false</code>) and tied it to the <code>window</code> object, just before I append the language Javascript to the <code>head</code>, i.e. (from the example above)</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">script.<span
style="color: #660066;">src</span> <span
style="color: #339933;">=</span> <span
style="color: #3366CC;">&quot;../lang/translations.&quot;</span> <span
style="color: #339933;">+</span> current_lang <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">&quot;.js&quot;</span><span
style="color: #339933;">;</span><br
/> window.<span
style="color: #660066;">translationsLoaded</span> <span
style="color: #339933;">=</span> <span
style="color: #003366; font-weight: bold;">false</span><span
style="color: #339933;">;</span> <span
style="color: #006600; font-style: italic;">// add this in</span><br
/> document.<span
style="color: #660066;">getElementsByTagName</span><span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">&quot;head&quot;</span><span
style="color: #009900;">&#41;</span><span
style="color: #009900;">&#91;</span><span
style="color: #CC0000;">0</span><span
style="color: #009900;">&#93;</span>.<span
style="color: #660066;">appendChild</span><span
style="color: #009900;">&#40;</span>script<span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>Then, further down in my file where I have the <code>window.onload</code> I did:</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">window.<span
style="color: #000066;">onload</span> <span
style="color: #339933;">=</span> <span
style="color: #003366; font-weight: bold;">function</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><br
/> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// needed for IE - event firing before lang file has loaded.</span><br
/> &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// gets fired via the js lang file</span><br
/> &nbsp; &nbsp; <span
style="color: #000066; font-weight: bold;">if</span> <span
style="color: #009900;">&#40;</span><span
style="color: #000066; font-weight: bold;">typeof</span> window.<span
style="color: #660066;">translationsLoaded</span> <span
style="color: #339933;">==</span> <span
style="color: #3366CC;">'undefined'</span> <span
style="color: #339933;">||</span> <span
style="color: #339933;">!</span>window.<span
style="color: #660066;">translationsLoaded</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #000066; font-weight: bold;">return</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&#125;</span><br
/> &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// rest of function</span><br
/> &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// ...</span><br
/> <span
style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div><p>Then, finally at the end of my <code>translations.en.js</code> I added code to set the variable to <code>true</code> and a manual call to the <code>window.onload</code> function:</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #006600; font-style: italic;">// needed for IE, onload event was firing too early in frmupload.html</span><br
/> <span
style="color: #000066; font-weight: bold;">if</span> <span
style="color: #009900;">&#40;</span><span
style="color: #000066; font-weight: bold;">typeof</span> window.<span
style="color: #660066;">translationsLoaded</span> <span
style="color: #339933;">!=</span> <span
style="color: #3366CC;">'undefined'</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; window.<span
style="color: #660066;">translationsLoaded</span> <span
style="color: #339933;">=</span> <span
style="color: #003366; font-weight: bold;">true</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; window.<span
style="color: #000066;">onload</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div><h2>Conculsion</h2><p>It&#8217;s frustrating when IE (even modern IE8 and 9!) just don&#8217;t behave like all the other browser. Luckily, once you find the source of the problems, there&#8217;s usually some sort of work around.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2012/05/window-onload-firing-too-early-in-ie/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>php, error_log and newlines: a solution</title><link>http://www.drcoen.com/2012/03/php-error_log-and-newlines-a-solution/</link> <comments>http://www.drcoen.com/2012/03/php-error_log-and-newlines-a-solution/#comments</comments> <pubDate>Thu, 15 Mar 2012 19:21:26 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Bug solution]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[php]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=91</guid> <description><![CDATA[When it comes to coding and debugging, I generally keep things simple, opting for a basic text editor (Sublime Text 2 with Vim key-bindings being my current choice) and simple debug output statements when trying to track down a bug. With my current job, I deal with an API over AJAX so it&#8217;s not easy [...]]]></description> <content:encoded><![CDATA[<p>When it comes to coding and debugging, I generally keep things simple, opting for a basic text editor (<a
href="http://www.sublimetext.com/2">Sublime Text 2</a> with Vim key-bindings being my current choice) and simple debug output statements when trying to track down a bug. With my current job, I deal with an API over AJAX so it&#8217;s not easy to send debug statements to the browser, hence had been using a combination of PHP&#8217;s <code>error_log</code> and <code>print_r($var, 1)</code> to get the value of a variable on the server. When debugging this way, I&#8217;d usually be doing a <code>tail -f</code> on my error log file, monitoring changes to that as I go.</p><p>This was all fine, but got very frustrating when dealing with arrays, objects and even strings with newline characters. The reason for this frustration was that newline characters were being displayed in the error log as <code>\n</code> and no new line, so something like</p><div
class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/></div></td><td><div
class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #000088;">$var</span> <span
style="color: #339933;">=</span> <span
style="color: #990000;">array</span><span
style="color: #009900;">&#40;</span><span
style="color: #0000ff;">'zero'</span> <span
style="color: #339933;">=&gt;</span> <span
style="color: #cc66cc;">0</span><span
style="color: #339933;">,</span> <span
style="color: #0000ff;">'one'</span> <span
style="color: #339933;">=&gt;</span> <span
style="color: #cc66cc;">1</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #990000;">error_log</span><span
style="color: #009900;">&#40;</span><span
style="color: #990000;">print_r</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$var</span><span
style="color: #339933;">,</span> <span
style="color: #cc66cc;">1</span><span
style="color: #009900;">&#41;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>would produce:</p><div
class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Array\n(\n &nbsp; &nbsp;[zero] =&gt; 0\n &nbsp; &nbsp;[one] =&gt; 1\n)</div></td></tr></tbody></table></div><p>instead of the nicer:</p><div
class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/></div></td><td><div
class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Array<br
/> (<br
/> &nbsp; &nbsp; [zero] =&gt; 0<br
/> &nbsp; &nbsp; [one] =&gt; 1<br
/> )</div></td></tr></tbody></table></div><p>Not too bad for small arrays but for large objects it&#8217;s a nightmare! Googling around didn&#8217;t have an easy answer. I&#8217;m sure it&#8217;s some setting deep in php.ini or my Apache config, but I managed to come up with a pretty neat solution, which I&#8217;m going to document here.</p><p>I started by creating my own error log in <code>/tmp/derror</code> (David&#8217;s Error = derror!) and letting any one write to it (I realise this could be slightly cleaner/more secure):</p><div
class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/></div></td><td><div
class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #c20cb9; font-weight: bold;">touch</span> <span
style="color: #000000; font-weight: bold;">/</span>tmp<span
style="color: #000000; font-weight: bold;">/</span>derror<br
/> <span
style="color: #c20cb9; font-weight: bold;">chmod</span> <span
style="color: #000000;">766</span> <span
style="color: #000000; font-weight: bold;">/</span>tmp<span
style="color: #000000; font-weight: bold;">/</span>derror</div></td></tr></tbody></table></div><p>Next I needed a nice debug function to write to this file. I wrote one that&#8217;ll take any number of parameters and for each one, output the current time along side a dump of their value. If it&#8217;s an object or class, use print_r, otherwise just display the value:</p><div
class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/>13<br
/>14<br
/>15<br
/>16<br
/></div></td><td><div
class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #000000; font-weight: bold;">function</span> derror<span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; <span
style="color: #000088;">$f</span> <span
style="color: #339933;">=</span> <span
style="color: #990000;">fopen</span><span
style="color: #009900;">&#40;</span><span
style="color: #0000ff;">'/tmp/derror'</span><span
style="color: #339933;">,</span> <span
style="color: #0000ff;">'a'</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; <span
style="color: #b1b100;">foreach</span> <span
style="color: #009900;">&#40;</span><span
style="color: #990000;">func_get_args</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span> <span
style="color: #b1b100;">as</span> <span
style="color: #000088;">$obj</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; <span
style="color: #990000;">fwrite</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$f</span><span
style="color: #339933;">,</span> <span
style="color: #990000;">date</span><span
style="color: #009900;">&#40;</span><span
style="color: #0000ff;">'Y-m-d G:i:s'</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">.</span><span
style="color: #0000ff;">&quot;<span
style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; <span
style="color: #b1b100;">if</span> <span
style="color: #009900;">&#40;</span><span
style="color: #990000;">is_array</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$obj</span><span
style="color: #009900;">&#41;</span> <span
style="color: #339933;">||</span> <span
style="color: #990000;">is_object</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$obj</span><span
style="color: #009900;">&#41;</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #990000;">fwrite</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$f</span><span
style="color: #339933;">,</span> <span
style="color: #990000;">print_r</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$obj</span><span
style="color: #339933;">,</span><span
style="color: #cc66cc;">1</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">.</span><span
style="color: #0000ff;">&quot;<span
style="color: #000099; font-weight: bold;">\n</span><span
style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&#125;</span><br
/> &nbsp; &nbsp; <span
style="color: #b1b100;">else</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #990000;">fwrite</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$f</span><span
style="color: #339933;">,</span> <span
style="color: #000088;">$obj</span><span
style="color: #339933;">.</span><span
style="color: #0000ff;">&quot;<span
style="color: #000099; font-weight: bold;">\n</span><span
style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&#125;</span><br
/> &nbsp; <span
style="color: #009900;">&#125;</span><br
/> &nbsp; <span
style="color: #990000;">fclose</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$f</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #009900;">&#125;</span><br
/> <br
/> <span
style="color: #666666; font-style: italic;">// called like</span><br
/> derror<span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$var1</span><span
style="color: #339933;">,</span> <span
style="color: #000088;">$var2</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>So, that function works fine but after a while I realised by doing my <code>tail -f</code> on my new error file, I was missing out on the real server errors. So, I had 2 different terminal tabs open, flipping between them both, which got annoying after about 2 errors! Luckily, I quickly thought of a way around this: route PHP&#8217;s error logging to my new file. The way Apache and virtual hosts are set-up this was quite easy and you can even log to 2 different files, thus preserving your &#8216;normal&#8217; error file too. so, in your <code>/etc/apache/sites-available/default</code> or whatever, in the <code>&lt;Virtualhost:*.80&gt;</code> block for your site, copy the line for <code>CustomLog</code> and point that to your error file, i.e.</p><div
class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">CustomLog /tmp/derror combined</div></td></tr></tbody></table></div><p>This should now route all Apache errors to your new file, so you have the best of both worlds!</p><p>To prevent the file getting to big over time, I set-up a cron job to simply delete the file and create a new one every Monday morning.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2012/03/php-error_log-and-newlines-a-solution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>oAuth with the Twitter API in Ruby on Rails without a gem</title><link>http://www.drcoen.com/2011/12/oauth-with-the-twitter-api-in-ruby-on-rails-without-a-gem/</link> <comments>http://www.drcoen.com/2011/12/oauth-with-the-twitter-api-in-ruby-on-rails-without-a-gem/#comments</comments> <pubDate>Thu, 15 Dec 2011 22:57:56 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Code]]></category> <category><![CDATA[api]]></category> <category><![CDATA[oauth]]></category> <category><![CDATA[ruby]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=87</guid> <description><![CDATA[This post is a follow on from my previous post about the oAuth protocol in general in Ruby. Here I detail how to let a user authenticate themselves via Twitter to your web app, request a list of people they&#8217;re following (a GET operation) and how to follow a specific user (a POST operation). As [...]]]></description> <content:encoded><![CDATA[<p>This post is a follow on from <a
href="http://www.drcoen.com/2011/12/oauth-1-0-in-ruby-without-a-gem/">my previous post about the oAuth protocol in general in Ruby</a>. Here I detail how to let a user authenticate themselves via Twitter to your web app, request a list of people they&#8217;re following (a <code>GET</code> operation) and how to follow a specific user (a <code>POST</code> operation). As this is a follow-on from an earlier post, the following functions used here can be seen <a
href="./2011/12/oauth-1-0-in-ruby-without-a-gem/">there</a>:</p><ul><li><code>params(consumer_key)</code></li><li><code>generate_nonce(size)</code></li><li><code>signature_base_string(method, uri, params)</code></li><li><code>url_encode(string)</code></li><li><code>sign(key, base_string)</code></li><li><code>header(params)</code></li><li><code>request_data(header, base_uri, method, post_data=nil)</code></li></ul><h2>The Log-in Process</h2><p>When you sign up for an API key from <a
href="https://dev.twitter.com/" rel="nofollow">Twitter</a>, <a
href="http://www.yelp.com/developers" rel="nofollow">Yelp</a> etc. you&#8217;ll be given a Consumer Key and a Consumer Secret. You may also be given an Access Token and an Access Token secret, but that&#8217;s for you logging into your own account. If that&#8217;s all you wish to do, you can skip this section.</p><p>So, if you want to let a user log in to their Twitter (or whatever) account via your site, you need to get an access token. The process for this is as follows:</p><ol><li>You request a unique Request Token from Twitter for your &#8216;Log-in with Twitter&#8217; button</li><li>You use this request token, as well as where on your site you want the user to be re-directed back to after they&#8217;re authenticated, to build the URL the button points to</li><li>They click the &#8216;Log-in with Twitter&#8217; button on your site</li><li>The user is brought to Twitter where they enter their username and password</li><li>Twitter re-directs them back to your site, to the URL you gave them in step 2</li><li>Back at your site, you&#8217;ll now have an oAuth verifier</li><li>This can be used to get the user&#8217;s Twitter user info, which has been authenticated by Twitter</li></ol><h3>Step 1: Getting an oAuth request token for your current session</h3><p>Twitter&#8217;s URL for getting a request token from is <code>https://api.twitter.com/oauth/request_token</code>. The request for the token contains a number of parameters, which are then combined with the URL you&#8217;re going to be sending the data to and the method of your request (i.e. GET, POST etc.) to generate what&#8217;s called a base signature. At this point you don&#8217;t have an access token, so your signing key is simply your consumer secret followed by an &#8216;<code>&amp;</code>&#8216;. Using the functions I&#8217;ve mentioned earlier, this can be done as follows:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/>13<br
/>14<br
/>15<br
/>16<br
/>17<br
/>18<br
/>19<br
/>20<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">consumer_key = <span
style="color:#996600;">'abcdefghijklmnop'</span> <span
style="color:#008000; font-style:italic;"># Obtainable from your destination site's API admin panel</span><br
/> consumer_secret = <span
style="color:#996600;">'zyxwvutsrqponm'</span> <span
style="color:#008000; font-style:italic;"># As above</span><br
/> callback_url = <span
style="color:#996600;">'http://www.mysite.com/logged-in'</span><br
/> method = <span
style="color:#996600;">'POST'</span><br
/> uri = <span
style="color:#996600;">'https://api.twitter.com/oauth/request_token'</span><br
/> params = params<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_key<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_callback'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span>callback_url<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_signature'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span>sign<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_secret <span
style="color:#006600; font-weight:bold;">+</span> <span
style="color:#996600;">'&amp;'</span>, signature_base_string<span
style="color:#006600; font-weight:bold;">&#40;</span>method, uri, params<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> token_data = parse_string<span
style="color:#006600; font-weight:bold;">&#40;</span>request_data<span
style="color:#006600; font-weight:bold;">&#40;</span>header<span
style="color:#006600; font-weight:bold;">&#40;</span>params<span
style="color:#006600; font-weight:bold;">&#41;</span>, uri, method<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> auth_token, auth_token_secret = <span
style="color:#006600; font-weight:bold;">&#91;</span>token_data<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_token'</span><span
style="color:#006600; font-weight:bold;">&#93;</span>, token_data<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_token_secret'</span><span
style="color:#006600; font-weight:bold;">&#93;</span><span
style="color:#006600; font-weight:bold;">&#93;</span> <span
style="color:#008000; font-style:italic;"># save these values, they'll be used again later</span><br
/> <br
/> <span
style="color:#008000; font-style:italic;"># where parse_string is simply</span><br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> parse_string<span
style="color:#006600; font-weight:bold;">&#40;</span>str<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; ret = <span
style="color:#006600; font-weight:bold;">&#123;</span><span
style="color:#006600; font-weight:bold;">&#125;</span><br
/> &nbsp; str.<span
style="color:#CC0066; font-weight:bold;">split</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#996600;">'&amp;'</span><span
style="color:#006600; font-weight:bold;">&#41;</span>.<span
style="color:#9900CC;">each</span> <span
style="color:#9966CC; font-weight:bold;">do</span> <span
style="color:#006600; font-weight:bold;">|</span>pair<span
style="color:#006600; font-weight:bold;">|</span><br
/> &nbsp; &nbsp; key_and_val = pair.<span
style="color:#CC0066; font-weight:bold;">split</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#996600;">'='</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; &nbsp; ret<span
style="color:#006600; font-weight:bold;">&#91;</span>key_and_val<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#006666;">0</span><span
style="color:#006600; font-weight:bold;">&#93;</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = key_and_val<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#006666;">1</span><span
style="color:#006600; font-weight:bold;">&#93;</span><br
/> &nbsp; <span
style="color:#9966CC; font-weight:bold;">end</span><br
/> &nbsp; ret<br
/> <span
style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div><h3>Steps 2-5: Authenticating with Twitter</h3><p>Once you have your request/access token, the URL to direct your user to is simply:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">login_url = <span
style="color:#996600;">'https://api.twitter.com/oauth/authorize?oauth_token='</span><span
style="color:#006600; font-weight:bold;">+</span>auth_token</div></td></tr></tbody></table></div><p>You can use standard <code><%= link_to 'Login', @login_url %></code> to generate a HTML anchor in your ERB template or whatever you choose. The user will then be directed to Twitter, where they enter their log-in details and get directed back to your callback URL.</p><h3>Steps 6-7: Getting the user&#8217;s info</h3><p>When the user is directed back to your site, you&#8217;ll be sent an <code>oauth_verifier</code>. This can be obtained via Rails in your callback URL&#8217;s corresponding controller, via <code>params[:oauth_verifier]</code>. You need to use this to request their user info, as a final check before they&#8217;re fully logged in. This results in a new auth token (or what Twitter calls an access token) and auth token secret, which should replace your previous stored values. It is assumed the code below is stored in a model class, where you need to pass the auth verifier from your controller.</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">method = <span
style="color:#996600;">'POST'</span><br
/> base_uri = <span
style="color:#996600;">'https://api.twitter.com/oauth/access_token'</span><br
/> params = params<span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#006600; font-weight:bold;">&#41;</span> <span
style="color:#008000; font-style:italic;"># not to be confused with params in your controller</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_verifier'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = auth_verifier <span
style="color:#008000; font-style:italic;"># this does come from params in the controller</span><br
/> <span
style="color:#008000; font-style:italic;">#auth_token_secret here is from above</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_signature'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span>sign<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_secret <span
style="color:#006600; font-weight:bold;">+</span> <span
style="color:#996600;">'&amp;'</span> <span
style="color:#006600; font-weight:bold;">+</span> auth_token_secret, signature_base_string<span
style="color:#006600; font-weight:bold;">&#40;</span>method, uri, params<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> data = parse_string<span
style="color:#006600; font-weight:bold;">&#40;</span>request_data<span
style="color:#006600; font-weight:bold;">&#40;</span>header<span
style="color:#006600; font-weight:bold;">&#40;</span>params<span
style="color:#006600; font-weight:bold;">&#41;</span>, base_uri, method<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span></div></td></tr></tbody></table></div><p><code>data</code> will now contain an array with things such as <code>screen_name</code>, <code>user_id</code> etc. of the user who just logged in. It&#8217;ll also contain a new <code>oauth_token</code> and <code>oauth_token_secret</code>, which should be saved as they&#8217;ll be used again.</p><p>Now you have a fully validated user, who has authenticated you to access information on Twitter via their Twitter account. So now, let&#8217;s access some of that info.</p><h2>Getting the people a user is following (a GET request)</h2><p>The process for all GET requests is pretty similar and roughly follows what we&#8217;ve done before. We have our array of standard parameters. To this, each of the <code>GET</code> parameters are passed. We use our access token and consumer key &amp; secret to generate our oAuth signature, make the request and parse the response.</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">method = <span
style="color:#996600;">'GET'</span><br
/> uri = <span
style="color:#996600;">'https://api.twitter.com/1/friends/ids.json'</span><br
/> params = params<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_key<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <span
style="color:#008000; font-style:italic;"># Add the GET parameters here</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'cursor'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = <span
style="color:#996600;">'-1'</span> <span
style="color:#008000; font-style:italic;"># start at the beginning</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'user_id'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = user_id <span
style="color:#008000; font-style:italic;"># from 'data' array above</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_signature'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span>sign<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_secret <span
style="color:#006600; font-weight:bold;">+</span> <span
style="color:#996600;">'&amp;'</span> <span
style="color:#006600; font-weight:bold;">+</span> auth_token_secret, signature_base_string<span
style="color:#006600; font-weight:bold;">&#40;</span>method, uri, params<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> uri <span
style="color:#006600; font-weight:bold;">+</span>= <span
style="color:#996600;">'?cursor=-1&amp;user_id='</span> <span
style="color:#006600; font-weight:bold;">+</span> user_id <span
style="color:#008000; font-style:italic;"># Add in the GET parameters to the URL</span><br
/> followees = JSON.<span
style="color:#9900CC;">parse</span><span
style="color:#006600; font-weight:bold;">&#40;</span>request_data<span
style="color:#006600; font-weight:bold;">&#40;</span>header<span
style="color:#006600; font-weight:bold;">&#40;</span>params<span
style="color:#006600; font-weight:bold;">&#41;</span>, uri, method<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span></div></td></tr></tbody></table></div><h2>Following a specific user (a POST request)</h2><p>The process for a <code>POST</code> is pretty similar, the only difference being how you handle the parameters to the request. In the example below, I&#8217;m assuming you have the user ID of the person you want to follow and that it&#8217;s stored in a variable called <code>followee_user_id</code>.</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">method = <span
style="color:#996600;">'POST'</span><br
/> uri = <span
style="color:#996600;">'https://api.twitter.com/1/friendships/create.json'</span><br
/> params = params<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_key<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'user_id'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = followee_user_id<br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_signature'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span>sign<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_secret <span
style="color:#006600; font-weight:bold;">+</span> <span
style="color:#996600;">'&amp;'</span> <span
style="color:#006600; font-weight:bold;">+</span> auth_token_secret, signature_base_string<span
style="color:#006600; font-weight:bold;">&#40;</span>method, uri, params<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> resp = JSON.<span
style="color:#9900CC;">parse</span><span
style="color:#006600; font-weight:bold;">&#40;</span>request_data<span
style="color:#006600; font-weight:bold;">&#40;</span>header<span
style="color:#006600; font-weight:bold;">&#40;</span>params<span
style="color:#006600; font-weight:bold;">&#41;</span>, uri, method, <span
style="color:#996600;">'user_id='</span><span
style="color:#006600; font-weight:bold;">+</span>followee_user_id<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span></div></td></tr></tbody></table></div><p>So, assuming that was successful, the user should now be following the person with user ID <code>followee_user_id</code>.</p><h2>Conclusion</h2><p>Hopefully this will fill in some of the gaps in Twitter&#8217;s documentation. When coding this I found plenty of instances where the documentation would say something like &#8220;now sign the key&#8221;, without actually telling you how to sign it! Very confusing indeed.</p><p><strong>Disclaimer:</strong> I obviously wrote all this in proper Ruby on Rails classes and controllers, but have extracted the code out here to be presented in modular form. Thus, what&#8217;s here is not fully tested, or even elegant, but there should be enough to figure out what you need to do.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/12/oauth-with-the-twitter-api-in-ruby-on-rails-without-a-gem/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>oAuth 1.0 in Ruby without a gem</title><link>http://www.drcoen.com/2011/12/oauth-1-0-in-ruby-without-a-gem/</link> <comments>http://www.drcoen.com/2011/12/oauth-1-0-in-ruby-without-a-gem/#comments</comments> <pubDate>Sat, 10 Dec 2011 22:56:02 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Code]]></category> <category><![CDATA[api]]></category> <category><![CDATA[oauth]]></category> <category><![CDATA[ruby]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=81</guid> <description><![CDATA[Recently I decided to figure out what the oAuth 1.0 protocol was all about and try to implement it in Ruby, as part of a way a) to practice by Ruby on Rails, b) have a look at the Twitter API and c) use both to get an understanding of how websites let you log [...]]]></description> <content:encoded><![CDATA[<p>Recently I decided to figure out what the oAuth 1.0 protocol was all about and try to implement it in Ruby, as part of a way a) to practice by Ruby on Rails, b) have a look at the Twitter API and c) use both to get an understanding of how websites let you log in/comment via your Facebook/Twitter/Google etc. account, for potential use in future web projects. Sure there&#8217;s an oAuth gem out there, and a Twitter gem and probably a generic login gem (or if not, there&#8217;s an idea!) but I thought I&#8217;d get more out of the process by coding everything from scratch. So, first up is a generic overview of the oAuth protocol.</p><p>Each request will have a method (i.e. <code>GET</code>, <code>POST</code> etc.), a base URL to handle the request at the source site (Twitter, Yelp etc.) and a certain set of parameters. Every request I&#8217;ve dealt with has had the same 5 parameters, along with various other ones specific to the request you&#8217;re making. So, in Ruby, I&#8217;d have something like:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/>13<br
/>14<br
/>15<br
/>16<br
/>17<br
/>18<br
/>19<br
/>20<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">consumer_key = <span
style="color:#996600;">'abcdefghijklmnop'</span> <span
style="color:#008000; font-style:italic;"># Obtainable from your destination site's API admin panel</span><br
/> consumer_secret = <span
style="color:#996600;">'zyxwvutsrqponm'</span> <span
style="color:#008000; font-style:italic;"># As above</span><br
/> method = <span
style="color:#996600;">'GET'</span><br
/> uri = <span
style="color:#996600;">'https://api.site.com/resource/section.format'</span><br
/> params = params<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_key<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <br
/> <span
style="color:#008000; font-style:italic;"># These 5 parameters are common to all calls</span><br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> params<span
style="color:#006600; font-weight:bold;">&#40;</span>consumer_key<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; params = <span
style="color:#006600; font-weight:bold;">&#123;</span><br
/> &nbsp; &nbsp; <span
style="color:#996600;">'oauth_consumer_key'</span> <span
style="color:#006600; font-weight:bold;">=&gt;</span> consumer_key, <span
style="color:#008000; font-style:italic;"># Your consumer key</span><br
/> &nbsp; &nbsp; <span
style="color:#996600;">'oauth_nonce'</span> <span
style="color:#006600; font-weight:bold;">=&gt;</span> generate_nonce, <span
style="color:#008000; font-style:italic;"># A random string, see below for function</span><br
/> &nbsp; &nbsp; <span
style="color:#996600;">'oauth_signature_method'</span> <span
style="color:#006600; font-weight:bold;">=&gt;</span> <span
style="color:#996600;">'HMAC-SHA1'</span>, <span
style="color:#008000; font-style:italic;"># How you'll be signing (see later)</span><br
/> &nbsp; &nbsp; <span
style="color:#996600;">'oauth_timestamp'</span> <span
style="color:#006600; font-weight:bold;">=&gt;</span> <span
style="color:#CC00FF; font-weight:bold;">Time</span>.<span
style="color:#9900CC;">now</span>.<span
style="color:#9900CC;">getutc</span>.<span
style="color:#9900CC;">to_i</span>.<span
style="color:#9900CC;">to_s</span>, <span
style="color:#008000; font-style:italic;"># Timestamp</span><br
/> &nbsp; &nbsp; <span
style="color:#996600;">'oauth_version'</span> <span
style="color:#006600; font-weight:bold;">=&gt;</span> <span
style="color:#996600;">'1.0'</span> <span
style="color:#008000; font-style:italic;"># oAuth version</span><br
/> &nbsp; <span
style="color:#006600; font-weight:bold;">&#125;</span><br
/> <span
style="color:#9966CC; font-weight:bold;">end</span><br
/> <br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> generate_nonce<span
style="color:#006600; font-weight:bold;">&#40;</span>size=<span
style="color:#006666;">7</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; <span
style="color:#CC00FF; font-weight:bold;">Base64</span>.<span
style="color:#9900CC;">encode64</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#6666ff; font-weight:bold;">OpenSSL::Random</span>.<span
style="color:#9900CC;">random_bytes</span><span
style="color:#006600; font-weight:bold;">&#40;</span>size<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span>.<span
style="color:#CC0066; font-weight:bold;">gsub</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#006600; font-weight:bold;">/</span>\W<span
style="color:#006600; font-weight:bold;">/</span>, <span
style="color:#996600;">''</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <span
style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div><p>Next, you&#8217;ll need to add in any extra parameters to your <code>params</code> hash, e.g. your access token if you have it, and then combine all the above to generate a base string:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/>13<br
/>14<br
/>15<br
/>16<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'abc'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = <span
style="color:#996600;">'xyz'</span><br
/> signature_base_string = signature_base_string<span
style="color:#006600; font-weight:bold;">&#40;</span>method, uri, params<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <br
/> <span
style="color:#008000; font-style:italic;">#where signature_base_string function is:</span><br
/> <br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> signature_base_string<span
style="color:#006600; font-weight:bold;">&#40;</span>method, uri, params<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; <span
style="color:#008000; font-style:italic;"># Join up the parameters into one long URL-safe string of key value pairs</span><br
/> &nbsp; encoded_params = params.<span
style="color:#9900CC;">sort</span>.<span
style="color:#9900CC;">collect</span><span
style="color:#006600; font-weight:bold;">&#123;</span> <span
style="color:#006600; font-weight:bold;">|</span>k, v<span
style="color:#006600; font-weight:bold;">|</span> url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#996600;">&quot;#{k}=#{v}&quot;</span><span
style="color:#006600; font-weight:bold;">&#41;</span> <span
style="color:#006600; font-weight:bold;">&#125;</span>.<span
style="color:#9900CC;">join</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#996600;">'%26'</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; <span
style="color:#008000; font-style:italic;"># Join the above with your method and URL-safe destination URL</span><br
/> &nbsp; method <span
style="color:#006600; font-weight:bold;">+</span> <span
style="color:#996600;">'&amp;'</span> <span
style="color:#006600; font-weight:bold;">+</span> url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span>uri<span
style="color:#006600; font-weight:bold;">&#41;</span> <span
style="color:#006600; font-weight:bold;">+</span> <span
style="color:#996600;">'&amp;'</span> <span
style="color:#006600; font-weight:bold;">+</span> encoded_params<br
/> <span
style="color:#9966CC; font-weight:bold;">end</span><br
/> <br
/> <span
style="color:#008000; font-style:italic;"># I'm a PHP developer primarily, hence the name of this function!</span><br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#CC0066; font-weight:bold;">string</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp;<span
style="color:#CC00FF; font-weight:bold;">CGI</span>::escape<span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#CC0066; font-weight:bold;">string</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <span
style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div><p>Next up, you need to generate a signing key, which is a combination of your consumer secret and your access token for the current session, if you have one at this stage (you may not, if the user still hasn&#8217;t logged in yet: in that case, a blank string will suffice). With this signing key, you sign your signature base string to get your oauth signature:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">access_token <span
style="color:#006600; font-weight:bold;">||</span>= <span
style="color:#996600;">''</span> <span
style="color:#008000; font-style:italic;"># if not set, blank string</span><br
/> signing_key = consumer_secret <span
style="color:#006600; font-weight:bold;">+</span> <span
style="color:#996600;">'&amp;'</span> <span
style="color:#006600; font-weight:bold;">+</span> access_token<br
/> params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_signature'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = url_encode<span
style="color:#006600; font-weight:bold;">&#40;</span>sign<span
style="color:#006600; font-weight:bold;">&#40;</span>signing_key, signature_base_string<span
style="color:#006600; font-weight:bold;">&#41;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <br
/> <span
style="color:#008000; font-style:italic;"># where sign is:</span><br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> sign<span
style="color:#006600; font-weight:bold;">&#40;</span>key, base_string<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; digest = <span
style="color:#6666ff; font-weight:bold;">OpenSSL::Digest::Digest</span>.<span
style="color:#9900CC;">new</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#996600;">'sha1'</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; hmac = <span
style="color:#6666ff; font-weight:bold;">OpenSSL::HMAC</span>.<span
style="color:#9900CC;">digest</span><span
style="color:#006600; font-weight:bold;">&#40;</span>digest, key, base_string<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; <span
style="color:#CC00FF; font-weight:bold;">Base64</span>.<span
style="color:#9900CC;">encode64</span><span
style="color:#006600; font-weight:bold;">&#40;</span>hmac<span
style="color:#006600; font-weight:bold;">&#41;</span>.<span
style="color:#CC0066; font-weight:bold;">chomp</span>.<span
style="color:#CC0066; font-weight:bold;">gsub</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#006600; font-weight:bold;">/</span>\n<span
style="color:#006600; font-weight:bold;">/</span>, <span
style="color:#996600;">''</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <span
style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div><p>At this point, you&#8217;ve all your info nicely encoded in the <code>oauth_signature</code> using your private consumer secret. So, in a kind of public/private key partnership, you need to give the service your public consumer key, so it can validate the encoding of the <code>oauth_signature</code> at the destination:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">params<span
style="color:#006600; font-weight:bold;">&#91;</span><span
style="color:#996600;">'oauth_consumer_key'</span><span
style="color:#006600; font-weight:bold;">&#93;</span> = consumer_key <span
style="color:#008000; font-style:italic;"># from above</span></div></td></tr></tbody></table></div><p>So, you&#8217;re nearly ready to make your oAuth request. One final thing: all these parameters need to go into the Authorization line in your HTTP header, which is simply a matter of generating another <key=value> string, as well as indicating you&#8217;re using oAuth:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">header_string = header<span
style="color:#006600; font-weight:bold;">&#40;</span>params<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <br
/> &nbsp;<span
style="color:#008000; font-style:italic;"># where header is:</span><br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> header<span
style="color:#006600; font-weight:bold;">&#40;</span>params<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; header = <span
style="color:#996600;">&quot;OAuth &quot;</span><br
/> &nbsp; params.<span
style="color:#9900CC;">each</span> <span
style="color:#9966CC; font-weight:bold;">do</span> <span
style="color:#006600; font-weight:bold;">|</span>k, v<span
style="color:#006600; font-weight:bold;">|</span><br
/> &nbsp; &nbsp; header <span
style="color:#006600; font-weight:bold;">+</span>= <span
style="color:#996600;">&quot;#{k}=<span
style="color:#000099;">\&quot;</span>#{v}<span
style="color:#000099;">\&quot;</span>, &quot;</span><br
/> &nbsp; <span
style="color:#9966CC; font-weight:bold;">end</span><br
/> &nbsp; header.<span
style="color:#9900CC;">slice</span><span
style="color:#006600; font-weight:bold;">&#40;</span><span
style="color:#006666;">0</span>..<span
style="color:#006600; font-weight:bold;">-</span><span
style="color:#006666;">3</span><span
style="color:#006600; font-weight:bold;">&#41;</span> <span
style="color:#008000; font-style:italic;"># chop off last &quot;, &quot;</span><br
/> <span
style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div><p>So, to make your HTTP request, I wrote a generic function (<code>request_data</code>) that will do either a <code>GET</code> or a <code>POST</code>, make the request and return the response body:</p><div
class="codecolorer-container ruby default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/>13<br
/>14<br
/>15<br
/></div></td><td><div
class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">response = request_data<span
style="color:#006600; font-weight:bold;">&#40;</span>header_string, uri, method<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> <br
/> <span
style="color:#008000; font-style:italic;"># where request_data is</span><br
/> <span
style="color:#9966CC; font-weight:bold;">def</span> request_data<span
style="color:#006600; font-weight:bold;">&#40;</span>header, base_uri, method, post_data=<span
style="color:#0000FF; font-weight:bold;">nil</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; url = <span
style="color:#CC00FF; font-weight:bold;">URI</span>.<span
style="color:#9900CC;">parse</span><span
style="color:#006600; font-weight:bold;">&#40;</span>base_uri<span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; http = <span
style="color:#6666ff; font-weight:bold;">Net::HTTP</span>.<span
style="color:#9900CC;">new</span><span
style="color:#006600; font-weight:bold;">&#40;</span>url.<span
style="color:#9900CC;">host</span>, <span
style="color:#006666;">443</span><span
style="color:#006600; font-weight:bold;">&#41;</span> <span
style="color:#008000; font-style:italic;"># set to 80 if not using HTTPS</span><br
/> &nbsp; http.<span
style="color:#9900CC;">use_ssl</span> = <span
style="color:#0000FF; font-weight:bold;">true</span> <span
style="color:#008000; font-style:italic;"># ignore if not using HTTPS</span><br
/> &nbsp; <span
style="color:#9966CC; font-weight:bold;">if</span> method == <span
style="color:#996600;">'POST'</span><br
/> &nbsp; &nbsp; <span
style="color:#008000; font-style:italic;"># post_data here should be your encoded POST string, NOT an array</span><br
/> &nbsp; &nbsp; resp, data = http.<span
style="color:#9900CC;">post</span><span
style="color:#006600; font-weight:bold;">&#40;</span>url.<span
style="color:#9900CC;">path</span>, post_data, <span
style="color:#006600; font-weight:bold;">&#123;</span> <span
style="color:#996600;">'Authorization'</span> <span
style="color:#006600; font-weight:bold;">=&gt;</span> header <span
style="color:#006600; font-weight:bold;">&#125;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; <span
style="color:#9966CC; font-weight:bold;">else</span><br
/> &nbsp; &nbsp; resp, data = http.<span
style="color:#9900CC;">get</span><span
style="color:#006600; font-weight:bold;">&#40;</span>url.<span
style="color:#9900CC;">to_s</span>, <span
style="color:#006600; font-weight:bold;">&#123;</span> <span
style="color:#996600;">'Authorization'</span> <span
style="color:#006600; font-weight:bold;">=&gt;</span> header <span
style="color:#006600; font-weight:bold;">&#125;</span><span
style="color:#006600; font-weight:bold;">&#41;</span><br
/> &nbsp; <span
style="color:#9966CC; font-weight:bold;">end</span><br
/> &nbsp; resp.<span
style="color:#9900CC;">body</span><br
/> <span
style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div><p>And there you go. You should have a response from the API in whatever format you requested, be it JSON, XML or whatever. In my <a
href="http://www.drcoen.com/2011/12/oauth-with-the-twitter-api-in-ruby-on-rails-without-a-gem/">next post</a>, I&#8217;ll explain how to use the above specifically for the Twitter API.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/12/oauth-1-0-in-ruby-without-a-gem/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Favourite Interview Process</title><link>http://www.drcoen.com/2011/09/favourite-interview-process/</link> <comments>http://www.drcoen.com/2011/09/favourite-interview-process/#comments</comments> <pubDate>Fri, 16 Sep 2011 14:33:19 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[General]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=75</guid> <description><![CDATA[Last month I resigned my post from daft.ie and am about to take up a development position with dotMobi, a leading mobile Internet services company. I had done interviews with several places, while reading plenty of articles on various other companies&#8217; hiring practices. At the end of these couple of months, I came to the [...]]]></description> <content:encoded><![CDATA[<p>Last month I resigned my post from daft.ie and am about to take up a development position with <a
href="http://mtld.mobi">dotMobi</a>, a leading mobile Internet services company. I had done interviews with several places, while reading plenty of articles on various other companies&#8217; hiring practices. At the end of these couple of months, I came to the conclusion that in all my professional career, Daft had the best hiring process for a developer that I had ever both experienced and read about.</p><h3>The process</h3><h4>Initial interview</h4><p>First up, as with all jobs, you submit your resume/CV. This is then screened over by the development manager, who invites adequate candidates to a first-stage interview. This interview consists of him and another developer, basically going through the CV with the candidate, asking some general programming related questions, all just to try and get a better overview of the person, ensuring they pass the &#8220;no jerks&#8221; policy.</p><h4>Programming Assignment</h4><p><b>This is the main beauty of their hiring process</b>, and is discussed in more details below. Candidates are given an assignment to work on in their own time at home, typically over a weekend. The assignment asks the user build a simple web form, with one text input to take free-text search strings that a user might enter when searching for property. They even give sample queries, such as &#8220;2 beds for sale in Dublin&#8221;. This string is to be submitted to a PHP script where all the necessary data is to be parsed from the string. Once parsed, a call is to be made to the Daft database via their API in order to get a list of results back. This result set is then displayed to the user. Finally, they need to write-up their code, explaining what&#8217;s going on in simple English.</p><h4>Second Interview</h4><p>Assuming you do a good job in the assignment, you&#8217;re then invited back for a more formal interview with senior management (company of about 60 people), to discuss career aspirations, salary requirements etc.</p><h3>Why I think this is great</h3><h4>Skills it shows</h4><p>As mentioned earlier, the key part of the process is the programming assignment. First up, the initial entry form and data submission. Here the user can show their knowledge of web security, CSS, (X)HTML standards and more. While none of these are actual requirements, it&#8217;s an easy place to show existing, fundamental web knowledge.</p><p>Once the data&#8217;s at the server, cleaned and verified, relevant data blocks (e.g. area, for sale/to let, number of bedrooms etc.) need to be parsed from the string. There are a number of different ways to do this and gives the developer plenty of scope for flair. A certain amount of analysis is required here also, mapping the domain of real estate to known keywords and looking for these in the string.</p><p>You also need to try and spot any relevant areas (e.g. County Dublin, Galway City etc.) the user may have entered. Without going into too much detail (in case potential candidates are reading this), there&#8217;s a key optimisation when doing this via the API and it&#8217;s a great way to spot those who have been programming seriously for a few years. Even if a programmer doesn&#8217;t implement this optimisation, they should still be aware of the problem it solves; this awareness can come across in their second interview, which is also accepted.</p><p>Once you know what the user is searching for, you then need to build a call to Daft&#8217;s SOAP API. This is good because it usually requires the candidate install PHP&#8217;s SOAP interface. While not overly complicated, it&#8217;s not trivial either and shows that the candidate is able to play around on a UNIX machine. Using the API also illustrates a candidates ability to follow documentation and quickly get to grips with a new system. Finally, by building a query from your parsed data that can be understood by the API, the candidate again has a chance to show some good, tidy code.</p><p>After pulling data from the API, the candidate again has a chance to show off XHTML/CSS skills to display the results set. Further &#8216;enhancements&#8217; could be shown by doing all this over AJAX, without a page reload.</p><p>Finally, the candidate needs to document their code. This will illustrate communication skills, their attention to detail, writing skills (grammar, spelling) and more. Everyone in the software industry knows that communication is a large part of software development and it&#8217;s important to have good communicators on your team. Good code followed by an average write-up can often be less preferable than average code (which is generally easier to improve on) with a good write-up.</p><h4>Why it&#8217;s better than others</h4><p>While reading about other people&#8217;s interview experiences, one thing that stood out as annoying most developers is white-board coding, i.e. where you&#8217;re required to write some code on the fly, either on a white board or piece of paper. This a completely unrealistic situation and is asking a programmer to do something way outside their normal environment. Similar to this would be writing a program in the employer&#8217;s office in the space of an hour to 90 minutes; again this is wholly unrealistic as programmers are used to their own environment, have their own tools etc. The beauty of the Daft assignment is that it&#8217;s too tricky to do in less than two hours, plus they let you do it at home on your own machine. Yes, this does allow for potential plagiarism, but once you&#8217;re offered a job, you&#8217;re put on 6 months initial probation, so if you don&#8217;t code your assignment it&#8217;ll soon become obvious and they&#8217;ll have scope to not make you permanent.</p><p>Another great thing about it is that there&#8217;s no generic analytical questions such as &#8220;Why are man-holes round?&#8221; or &#8220;How many ties were sold in New York City last year?&#8221;. The value in asking these questions is surely waning these days, as they are easy enough to prepare for and people have learnt to expect them. Good programmers need to be good at analysis, but enough information about a candidates skills can be gleaned from how they approach the assignment.</p><p>Finally, there&#8217;s no over-bloated 7 round interview process. From the 2 interviews a candidate does, coupled with the assignment, it&#8217;s very easy to see what a person is like and that they&#8217;ve a decent level of programming competency.</p><h3>One flaw</h3><p>Not everything&#8217;s perfect and after chatting to my manager about the interview process, in preparation for this blog post, he pointed out that it&#8217;s poor at highlighting any &#8220;rockstar&#8221; programmers, as well as any existing systems administration skills. So, if you have 2 people competing against each other, one a decent programmer, the other amazing, it can be hard to differentiate between the 2; what&#8217;ll happen more often than not is that the &#8216;nicer&#8217; one will be offered the job first.</p><h3>Conclusion</h3><p>From the above, it should be easy to see that current interview processes are far too complicated. 2 interviews will always be the least that&#8217;s required, but when you throw in a slightly complicated programming assignment, there shouldn&#8217;t be need for much more. The assignment&#8217;s a good way to test programming competency while the interviews are good to test a person&#8217;s likeability and career aspirations.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/09/favourite-interview-process/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>MySQL reached max integer limit</title><link>http://www.drcoen.com/2011/08/mysql-reached-max-integer-limit/</link> <comments>http://www.drcoen.com/2011/08/mysql-reached-max-integer-limit/#comments</comments> <pubDate>Tue, 23 Aug 2011 12:39:20 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Bug solution]]></category> <category><![CDATA[Code]]></category> <category><![CDATA[mysql]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=71</guid> <description><![CDATA[Whenever anything generates a MySQL error at work, the whole technical team gets an email about it, with full debug info. We recently got one for an area that I look after, so it was up to me to investigate. The title of the error was a slightly cryptic Error: Duplicate entry &#8217;0&#8242; for key [...]]]></description> <content:encoded><![CDATA[<p>Whenever anything generates a MySQL error at work, the whole technical team gets an email about it, with full debug info. We recently got one for an area that I look after, so it was up to me to investigate. The title of the error was a slightly cryptic</p><blockquote><p>Error: Duplicate entry &#8217;0&#8242; for key 1</p></blockquote><p>Clearly this had something to do with the primary key, which was a simple unique integer <code>ID</code>. As this is a pretty large table, I had a feeling that we had reached the upper limit of what could be stored for the field type (MySQL&#8217;s <code>MEDIUMINT</code>, signed). Looking at the maximum value for the <code>ID</code>, I saw it was <code>8388607</code>; according to <a
href="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html">this table on the MySQL website</a>, this value is the maximum that can be stored in that type of field, so this was clearly the problem. (N.B. an auto-incrementing field shouldn&#8217;t ever be defined as signed, as you&#8217;ll never go into the negative indices, but that was done before I came along!)</p><p>The solution? Surely a simple readjusting of the key to be unsigned, or to further future proofing, changing to the larger <code>INT</code>&#8230; That&#8217;s what I thought and quickly (in test first, of course!) did a</p><div
class="codecolorer-container mysql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="mysql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #990099; font-weight: bold;">ALTER</span> <span
style="color: #990099; font-weight: bold;">TABLE</span> table_name CHANGE <span
style="color: #990099; font-weight: bold;">COLUMN</span> id id <span
style="color: #999900; font-weight: bold;">MEDIUMINT</span> <span
style="color: #FF9900; font-weight: bold;">UNSIGNED</span> <span
style="color: #CC0099; font-weight: bold;">NOT</span> <span
style="color: #9900FF; font-weight: bold;">NULL</span> <span
style="color: #FF9900; font-weight: bold;">AUTO_INCREMENT</span></div></td></tr></tbody></table></div><p>This should then change the maximum value allowed in the <code>ID</code> field to <code>16777215</code>. So, to test this, I went to insert a row, specifying <code>NULL</code> for the primary key value. However, I still got the same error. Doing a <code>DESC</code> on the table told me that the <code>ID</code> field had been changed to <code>MEDIUMINT UNSIGNED</code> correctly, so that wasn&#8217;t the issue. After further research I determined that what happend was that MySQL&#8217;s internal counter for that <code>auto increment</code> field was still set to 0, due to the rollover caused after reaching the maximum integer value. To overcome this, you need to point the internal counter back to where it should be, i.e. the current maximum value of your <code>ID</code> field, as follows:</p><div
class="codecolorer-container mysql default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="mysql codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #990099; font-weight: bold;">ALTER</span> <span
style="color: #990099; font-weight: bold;">TABLE</span> table_name <span
style="color: #FF9900; font-weight: bold;">AUTO_INCREMENT</span> <span
style="color: #CC0099;">=</span> <span
style="color: #008080;">8388608</span></div></td></tr></tbody></table></div><p>So, you set it to a value that&#8217;s one greater than the current maximum <code>ID</code>.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/08/mysql-reached-max-integer-limit/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>jQuery Mobile and Dynamic Data</title><link>http://www.drcoen.com/2011/05/jquery-mobile-and-dynamic-data/</link> <comments>http://www.drcoen.com/2011/05/jquery-mobile-and-dynamic-data/#comments</comments> <pubDate>Mon, 23 May 2011 20:34:01 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Code]]></category> <category><![CDATA[jquery]]></category> <category><![CDATA[jquery-mobile]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=64</guid> <description><![CDATA[UPDATE: I&#8217;ve recently been asked by entertainment.ie to stop scraping thier licensed data, to which I&#8217;ve duly agreed. Thus, the app is no longer live. However, the lessons learned below are still valid. END Haven&#8217;t posted for a while, mainly because I&#8217;ve been busy trying to teach myself Ruby on Rails, so haven&#8217;t created anything [...]]]></description> <content:encoded><![CDATA[<p><b>UPDATE:</b> I&#8217;ve recently been asked by entertainment.ie to stop scraping thier licensed data, to which I&#8217;ve duly agreed. Thus, the app is no longer live. However, the lessons learned below are still valid. <b>END</b></p><p>Haven&#8217;t posted for a while, mainly because I&#8217;ve been busy trying to teach myself Ruby on Rails, so haven&#8217;t created anything new in my spare time. Have come up with a few interesting fixes/ways to do things in relation to Facebook code in work though, so will hopefully do a post on those in the near future.<br
/> In the meantime, I wrote a very small little web application last week using the pretty cool <a
href="http://jquerymobile.com/">jQuery Mobile</a> framework. The app, called What&#8217;s on now (link removed, see UPDATE above), is simply a list of what&#8217;s on now and next on Ireland&#8217;s 17 basic cable channels. The data is pulled from a similar page on entertainment.ie, with the unnecessary channels filtered out. At the moment the app is pretty simple, but I plan to add to it over time (e.g. to add an option for the non-basic channels), updating this article as I go.</p><p>I did this mainly to have a quick go with jQuery Mobile, to see what it could do. I could&#8217;ve used PHP and built a mobile-sized HTML page, but it&#8217;s always good to try new things! Most of the development was pretty straight forward; however, because the data is retrieved dynamically every time the page is loaded, there&#8217;s a couple of tricks you need to apply to get the jQuery Mobile framework to do it&#8217;s magic.</p><p>The main page you&#8217;re greeted with is simply a glorified un-ordered list of programmes, with separator list items to distinguish the channels. I&#8217;m not going to go into the details of how you need to structure a page (see links at the end of this post) but here&#8217;s a snippet of the HTML:</p><div
class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/></div></td><td><div
class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">body</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">ul</span> <span
style="color: #000066;">id</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;channels&quot;</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;listview&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">li</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;list-divider&quot;</span>&gt;</span>RTE One<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">li</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">li</span>&gt;&lt;<span
style="color: #000000; font-weight: bold;">a</span> <span
style="color: #000066;">href</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;#RTE-One-1&quot;</span>&gt;</span>21:00: 9 O'Clock News<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">li</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">li</span>&gt;&lt;<span
style="color: #000000; font-weight: bold;">a</span> <span
style="color: #000066;">href</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;#RTE-One-2&quot;</span>&gt;</span>21:35: Prime Time<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">li</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">li</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;list-divider&quot;</span>&gt;</span>RTE Two<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">li</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; .. etc.<br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">ul</span>&gt;</span></div></td></tr></tbody></table></div><p>When the page loads, <code>ul#channels</code> is empty. The data is called via a jQuery GET, which gets over cross-domain restrictions by using <a
href="http://developer.yahoo.com/yui/">YUI</a>, thanks to the <a
href="http://james.padolsey.com/javascript/cross-domain-requests-with-jquery/">Cross-Domain AJAX mod</a>. The relevant data is filtered out and formatted and each of the <code>li</code>&#8216;s are built and inserted into <code>#channels</code>. At this point, if you look at the page in your browser, it&#8217;ll still look like an ordinary list &#8211; you need to tell jQuery to work it&#8217;s magic on the dynamically created data. In this instance it&#8217;s done as follows:</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">&quot;#channels&quot;</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">listview</span><span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">&quot;refresh&quot;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>Once I had my list of programmes, I thought I may as well add the info for each program, seeing as I already had the data at my disposal. The route I decided to go down here was to create new &#8216;page&#8217; <code>div</code>&#8216;s for each program, each one having it&#8217;s own ID, then link to each of these pages from the <code>li</code>&#8216;s. Again, the scope of building one of these pages is beyond this blog post and well documented elsewhere, but here&#8217;s a quick sample:</p><div
class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/></div></td><td><div
class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;page&quot;</span> <span
style="color: #000066;">id</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;RTE-One-1&quot;</span> data-url<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;RTE-One-1&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;header&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">h1</span>&gt;</span>RTE one<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;content&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">h2</span>&gt;</span>9 O'Clock News: 21:00<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; An update on the latest domestic and international events of the day.<br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;footer&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #ddbb00;">&amp;copy;</span> David Coen 2011<br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span><br
/> <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></td></tr></tbody></table></div><p>This is simply added to the body using <code>$('body').append(page);</code> (where the variable page is a string of HTML such as the above). So, again here you need to tell jQuery Mobile that you&#8217;ve added a new page, so it can do it&#8217;s magic. This is achieved by the one simple line:</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'#RTE-One-1'</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">page</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>Hopefully this post will clear up a couple of things for anyone using jQuery Mobile with dynamically generated data. As I promised, here are some links of articles that helped me get a better understanding of the framework:</p><ul><li><a
href="http://msdn.microsoft.com/en-US/scriptjunkie/hh144955.aspx">http://msdn.microsoft.com/en-US/scriptjunkie/hh144955.aspx</a></li><li><a
href="http://jquerymobile.com/demos/1.0a4.1/">http://jquerymobile.com/demos/1.0a4.1/</a></li><li><a
href="http://www.elated.com/articles/jquery-mobile-what-can-it-do-for-you/">http://www.elated.com/articles/jquery-mobile-what-can-it-do-for-you/</a></li></ul><h2>Full implementation code (UPDATE 2)</h2><p>I was requested by @danny to post the full source code, seeing as the app is actually no longer available, so I&#8217;ve decided to put most of it here. I excluded some of the scrape JS (as indicated in the code comments) to prevent the app being re-used somewhere else.</p><p>So, first up, is the initial HTML page, with header and footer blocks, an empty content block and the JS and CSS includes:</p><div
class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;height:300px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/>13<br
/>14<br
/>15<br
/>16<br
/>17<br
/>18<br
/>19<br
/>20<br
/>21<br
/>22<br
/>23<br
/>24<br
/>25<br
/>26<br
/>27<br
/></div></td><td><div
class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">html</span>&gt;</span><br
/> &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">head</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">title</span>&gt;</span>What's on now<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">title</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">link</span> <span
style="color: #000066;">rel</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;stylesheet&quot;</span> <span
style="color: #000066;">href</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.css&quot;</span> <span
style="color: #66cc66;">/</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">script</span> <span
style="color: #000066;">type</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;text/javascript&quot;</span> <span
style="color: #000066;">src</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;./jquery.min.js&quot;</span>&gt;&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">script</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">script</span> <span
style="color: #000066;">type</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;text/javascript&quot;</span> <span
style="color: #000066;">src</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;./jquery-mobile.min.js&quot;</span>&gt;&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">script</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">script</span> <span
style="color: #000066;">type</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;text/javascript&quot;</span> <span
style="color: #000066;">src</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;./whatson.js&quot;</span>&gt;&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">script</span>&gt;</span><br
/> &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">head</span>&gt;</span><br
/> &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">body</span>&gt;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;page&quot;</span> <span
style="color: #000066;">id</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;home&quot;</span>&gt;</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;header&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">h1</span>&gt;</span>What's on now<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;content&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">ul</span> <span
style="color: #000066;">id</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;channels&quot;</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;listview&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">div</span> data-role<span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;footer&quot;</span> <span
style="color: #000066;">style</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;text-align: center;&quot;</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #000000; font-weight: bold;">a</span> <span
style="color: #000066;">href</span><span
style="color: #66cc66;">=</span><span
style="color: #ff0000;">&quot;http://www.drcoen.com&quot;</span>&gt;</span><span
style="color: #ddbb00;">&amp;copy;</span> David Coen 2011<span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">a</span>&gt;</span><br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span><br
/> <br
/> &nbsp; &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">div</span>&gt;</span><br
/> &nbsp; <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">body</span>&gt;</span><br
/> <span
style="color: #009900;">&lt;<span
style="color: #66cc66;">/</span><span
style="color: #000000; font-weight: bold;">html</span>&gt;</span></div></td></tr></tbody></table></div><p>Next up is the javascript file, <code>whatson.js</code> in the above. Don&#8217;t forget, the <code>$.ajax</code> call has been overwritten by the Cross-Domain AJAX plug-in I mentioned earlier. Addtionally, I&#8217;ve used a few functions from <a
href="http://phpjs.org">php.js.</a> to replicate this functionality in JS, namely <code>str_replace</code>, <code>in_array</code> and <code>trim</code>. I&#8217;ve excluded them here but they can be found in the php.js website.</p><p>Also, just to re-clarify, the page i was scraping had a list of channels and programs that were on now (prog1) and next (prog2).</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;height:300px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/>5<br
/>6<br
/>7<br
/>8<br
/>9<br
/>10<br
/>11<br
/>12<br
/>13<br
/>14<br
/>15<br
/>16<br
/>17<br
/>18<br
/>19<br
/>20<br
/>21<br
/>22<br
/>23<br
/>24<br
/>25<br
/>26<br
/>27<br
/>28<br
/>29<br
/>30<br
/>31<br
/>32<br
/>33<br
/>34<br
/>35<br
/>36<br
/>37<br
/>38<br
/>39<br
/>40<br
/>41<br
/>42<br
/>43<br
/>44<br
/>45<br
/>46<br
/>47<br
/>48<br
/>49<br
/>50<br
/>51<br
/>52<br
/>53<br
/>54<br
/>55<br
/>56<br
/>57<br
/>58<br
/>59<br
/>60<br
/>61<br
/>62<br
/>63<br
/>64<br
/>65<br
/>66<br
/>67<br
/>68<br
/>69<br
/>70<br
/>71<br
/>72<br
/>73<br
/>74<br
/>75<br
/>76<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span
style="color: #009900;">&#40;</span>document<span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">ready</span><span
style="color: #009900;">&#40;</span><span
style="color: #003366; font-weight: bold;">function</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; <span
style="color: #003366; font-weight: bold;">var</span> cable_channels <span
style="color: #339933;">=</span> <span
style="color: #009900;">&#91;</span><br
/> &nbsp; &nbsp; <span
style="color: #3366CC;">'RTE One'</span><span
style="color: #339933;">,</span><br
/> &nbsp; &nbsp; <span
style="color: #3366CC;">'RTE Two'</span><span
style="color: #339933;">,</span><br
/> &nbsp; &nbsp; <span
style="color: #3366CC;">'BBC One'</span><span
style="color: #339933;">,</span><br
/> &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// etc......</span><br
/> &nbsp; <span
style="color: #009900;">&#93;</span><span
style="color: #339933;">;</span><br
/> &nbsp; $.<span
style="color: #660066;">mobile</span>.<span
style="color: #660066;">pageLoading</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; $.<span
style="color: #660066;">ajax</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; url<span
style="color: #339933;">:</span> <span
style="color: #006600; font-style: italic;">// URL for the data</span><br
/> &nbsp; &nbsp; type<span
style="color: #339933;">:</span> <span
style="color: #3366CC;">'GET'</span><span
style="color: #339933;">,</span><br
/> &nbsp; &nbsp; success<span
style="color: #339933;">:</span> <span
style="color: #003366; font-weight: bold;">function</span><span
style="color: #009900;">&#40;</span>data<span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; &nbsp; html <span
style="color: #339933;">=</span> $<span
style="color: #009900;">&#40;</span>data<span
style="color: #009900;">&#91;</span><span
style="color: #3366CC;">'responseText'</span><span
style="color: #009900;">&#93;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// for each channel scrapped</span><br
/> &nbsp; &nbsp; &nbsp; $<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'td.listing-channel'</span><span
style="color: #339933;">,</span> html<span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">each</span><span
style="color: #009900;">&#40;</span><span
style="color: #003366; font-weight: bold;">function</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #003366; font-weight: bold;">var</span> channel <span
style="color: #339933;">=</span> <span
style="color: #006600; font-style: italic;">// code omitted</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #003366; font-weight: bold;">var</span> prog1_start<span
style="color: #339933;">,</span> prog2_start<span
style="color: #339933;">,</span> prog1<span
style="color: #339933;">,</span> prog2<span
style="color: #339933;">,</span> prog1_name<span
style="color: #339933;">,</span> prog2_name<span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// if it's a channel I'm interested in</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #000066; font-weight: bold;">if</span> <span
style="color: #009900;">&#40;</span>in_array<span
style="color: #009900;">&#40;</span>channel<span
style="color: #339933;">,</span> cable_channels<span
style="color: #009900;">&#41;</span><span
style="color: #009900;">&#41;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// get the name, start time and description of the program currently being shown on the channel</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog1_start <span
style="color: #339933;">=</span> <span
style="color: #006600; font-style: italic;">// start time of 1st program - code omitted</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog1_name <span
style="color: #339933;">=</span> <span
style="color: #006600; font-style: italic;">// name of 1st program - code omitted</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog1 <span
style="color: #339933;">=</span> <span
style="color: #006600; font-style: italic;">// description of 1st program - code omitted</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// do the same for the one on after it</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog2_start <span
style="color: #339933;">=</span> <span
style="color: #006600; font-style: italic;">// start time of 2nd program - code omitted</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog2_name <span
style="color: #339933;">=</span> <span
style="color: #006600; font-style: italic;">// name of 2nd program - code omitted</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog2 <span
style="color: #339933;">=</span> <span
style="color: #006600; font-style: italic;">// description of 2nd program - code omitted</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// replace spaces with '-' for a valid #id</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #003366; font-weight: bold;">var</span> id <span
style="color: #339933;">=</span> str_replace<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">' '</span><span
style="color: #339933;">,</span> <span
style="color: #3366CC;">'-'</span><span
style="color: #339933;">,</span> channel<span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">//create new block on the main page for our channel and it's 2 programs</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #003366; font-weight: bold;">var</span> li <span
style="color: #339933;">=</span> <span
style="color: #3366CC;">'&lt;li data-role=&quot;list-divider&quot;&gt;'</span> <span
style="color: #339933;">+</span> channel <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'&lt;/li&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;li&gt;&lt;a href=&quot;#'</span> <span
style="color: #339933;">+</span> id <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'-1&quot;&gt;'</span> <span
style="color: #339933;">+</span> prog1_start <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">': '</span> <span
style="color: #339933;">+</span> prog1_name <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'&lt;/a&gt;&lt;/li&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;li&gt;&lt;a href=&quot;#'</span> <span
style="color: #339933;">+</span> id <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'-2&quot;&gt;'</span> <span
style="color: #339933;">+</span> prog2_start <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">': '</span> <span
style="color: #339933;">+</span> prog2_name <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'&lt;/a&gt;&lt;/li&gt;'</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'#channels'</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">append</span><span
style="color: #009900;">&#40;</span>li<span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// create a new page for the program description - clicking on the program in the &lt;li&gt; above will</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// bring you to this new description page</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #003366; font-weight: bold;">var</span> page <span
style="color: #339933;">=</span> <span
style="color: #3366CC;">'&lt;div data-role=&quot;page&quot; id=&quot;'</span><span
style="color: #339933;">+</span>id<span
style="color: #339933;">+</span><span
style="color: #3366CC;">'-1&quot; data-url=&quot;'</span><span
style="color: #339933;">+</span>id<span
style="color: #339933;">+</span><span
style="color: #3366CC;">'-1&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;div data-role=&quot;header&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;h1&gt;'</span> <span
style="color: #339933;">+</span> channel <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'&lt;/h1&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;/div&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;div data-role=&quot;content&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;h2&gt;'</span> <span
style="color: #339933;">+</span> prog1_name <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">': '</span> <span
style="color: #339933;">+</span> prog1_start <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'&lt;/h2&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog1 <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;/div&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;div data-role=&quot;footer&quot; style=&quot;text-align: center;&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;a href=&quot;http://www.drcoen.com&quot;&gt;&amp;copy; David Coen 2011&lt;/a&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;/div&gt;'</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'body'</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">append</span><span
style="color: #009900;">&#40;</span>page<span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'#'</span><span
style="color: #339933;">+</span>id<span
style="color: #339933;">+</span><span
style="color: #3366CC;">'-1'</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">page</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #006600; font-style: italic;">// Do same again for 2nd program</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; page <span
style="color: #339933;">=</span> <span
style="color: #3366CC;">'&lt;div data-role=&quot;page&quot; id=&quot;'</span><span
style="color: #339933;">+</span>id<span
style="color: #339933;">+</span><span
style="color: #3366CC;">'-2&quot; data-url=&quot;'</span><span
style="color: #339933;">+</span>id<span
style="color: #339933;">+</span><span
style="color: #3366CC;">'-2&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;div data-role=&quot;header&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;h1&gt;'</span> <span
style="color: #339933;">+</span> channel <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'&lt;/h1&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;/div&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;div data-role=&quot;content&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;h2&gt;'</span> <span
style="color: #339933;">+</span> prog2_name <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">': '</span> <span
style="color: #339933;">+</span> prog2_start <span
style="color: #339933;">+</span> <span
style="color: #3366CC;">'&lt;/h2&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prog2 <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;/div&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;div data-role=&quot;footer&quot; style=&quot;text-align: center;&quot;&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;a href=&quot;http://www.drcoen.com&quot;&gt;&amp;copy; David Coen 2011&lt;/a&gt;'</span> <span
style="color: #339933;">+</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #3366CC;">'&lt;/div&gt;'</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'body'</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">append</span><span
style="color: #009900;">&#40;</span>page<span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">'#'</span><span
style="color: #339933;">+</span>id<span
style="color: #339933;">+</span><span
style="color: #3366CC;">'-2'</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">page</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&#125;</span><br
/> &nbsp; &nbsp; &nbsp; <span
style="color: #009900;">&#125;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; $<span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">&quot;#channels&quot;</span><span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">listview</span><span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">&quot;refresh&quot;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; $.<span
style="color: #660066;">mobile</span>.<span
style="color: #660066;">pageLoading</span><span
style="color: #009900;">&#40;</span><span
style="color: #003366; font-weight: bold;">true</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span> <span
style="color: #006600; font-style: italic;">// kill the page loading modal</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&#125;</span><br
/> &nbsp; <span
style="color: #009900;">&#125;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #009900;">&#125;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span></div></td></tr></tbody></table></div><p>I realise this code could be alot cleaner, but the app was still in it&#8217;s early stages before I was asked to take it down, thus I haven&#8217;t spent time tidying it up. Hopefully there&#8217;s enough here to figure out how to do what you need!</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/05/jquery-mobile-and-dynamic-data/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Regular expression (regex) to remove double encoding of html entities</title><link>http://www.drcoen.com/2011/03/regular-expression-regex-to-remove-double-encoding-of-html-entities/</link> <comments>http://www.drcoen.com/2011/03/regular-expression-regex-to-remove-double-encoding-of-html-entities/#comments</comments> <pubDate>Wed, 30 Mar 2011 18:43:47 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Code]]></category> <category><![CDATA[php regex regular-expression html]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=60</guid> <description><![CDATA[When you have users copying and pasting in data to forms on your website, which then gets stored in your database, you invariably end up with all sorts of ways of encoding and storing special characters. Ideally, these will end up in your database as the correct characters (such as &#8364; for the euro symbol), [...]]]></description> <content:encoded><![CDATA[<p>When you have users copying and pasting in data to forms on your website, which then gets stored in your database, you invariably end up with all sorts of ways of encoding and storing special characters. Ideally, these will end up in your database as the correct characters (such as &euro; for the euro symbol), which will then get encoded as HTML entities when you display this data on your website (so, &euro; becomes <code>&amp;euro;</code> in the HTML).</p><p>However, with older systems, especially those built in-house, you end up with the HTML entity version of certain characters in your database. It&#8217;s pretty much a fact of web development. Let&#8217;s use the example of a string that says &#8220;Price: &euro;100&#8243; but gets stored in the database as &#8220;Price: &amp;euro;100&#8243;. When you go to display this text on your encoded web-page, you end up seeing things such as &#8220;Price: &amp;amp;euro;100&#8243; in your browser. This is a result of double encoding, as the <code>&#038;</code> in <code>&amp;euro;</code> is first getting encoded as <code>&amp;amp;</code>.</p><p>In order to remove these, I came up with the following function, that uses a simple regular expression to tidy such instances up.</p><div
class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/>2<br
/>3<br
/>4<br
/></div></td><td><div
class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #000000; font-weight: bold;">function</span> remove_double_encoding<span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$in</span><span
style="color: #009900;">&#41;</span><br
/> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; <span
style="color: #b1b100;">return</span> <span
style="color: #990000;">preg_replace</span><span
style="color: #009900;">&#40;</span><span
style="color: #0000ff;">'/&amp;amp;([a-zA-Z0-9]{2,7});/'</span><span
style="color: #339933;">,</span> <span
style="color: #0000ff;">'&amp;$1;'</span><span
style="color: #339933;">,</span> <span
style="color: #000088;">$in</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div><p>What this does is looks for any 2 to 7 letter strings with <code>&amp;amp;</code> immediately before them and <code>;</code> immediately after. When it finds a match, it simply replaces the <code>&amp;amp;</code> with <code>&amp;</code>. It does this for all instances in your input string.</p><p><b>Update:</b> Forgot that you can also have purely numeric codes here, so added &#8217;0-9&#8242; to the regex.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/03/regular-expression-regex-to-remove-double-encoding-of-html-entities/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Google Maps Zoom Control missing in Internet Explorer (IE): a solution</title><link>http://www.drcoen.com/2011/02/google-maps-zoom-control-missing-in-internet-explorer-ie-a-solution/</link> <comments>http://www.drcoen.com/2011/02/google-maps-zoom-control-missing-in-internet-explorer-ie-a-solution/#comments</comments> <pubDate>Wed, 23 Feb 2011 19:59:21 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Bug solution]]></category> <category><![CDATA[bug]]></category> <category><![CDATA[google]]></category> <category><![CDATA[google-maps]]></category> <category><![CDATA[javascript]]></category> <category><![CDATA[jquery]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=57</guid> <description><![CDATA[When I was working on rebuilding daft.ie&#8217;s mapping system for the modern web, it involved writing alot of Javascript (JS) code and loading this via a couple of JS source files, one external one from Google (i.e. the core Google Maps JS) and another from our own web-servers. It all worked fine in most browsers, [...]]]></description> <content:encoded><![CDATA[<p>When I was working on rebuilding daft.ie&#8217;s mapping system for the modern web, it involved writing alot of Javascript (JS) code and loading this via a couple of JS source files, one external one from Google (i.e. the core Google Maps JS) and another from our own web-servers.</p><p>It all worked fine in most browsers, except of course Internet Explorer (IE). To be fair, IE8 was fine; however, seemingly at random, the zoom control would sometimes not appear on the map for IE7 and IE6 and you&#8217;d get one of IE&#8217;s very unhelpful error messages. At Daft we like to ensure that the site is available and consistent on all browsers, so it was imperative to get this issue sorted.</p><p>Because of the aforementioned unhelpful error messages, it proved to be a very difficult bug to nail down. I began to suspect that it was due to the code from Google loading <em>after</em> the map is set-up in the daft.ie hosted file, i.e. IE was calling Google-specific functions before it had the code. As it was all wrapped in a jQuery <code>$(document).ready</code> I didn&#8217;t think this could happen, but turns out that in the older versions of IE it could! I tried moving the JS around, loading the Daft-specific JS as late as possible, to try and give the Google JS the maximum amount of time to load, but that was to no avail.</p><p>So, I needed to find a way to load the Daft JS when I was <em>100% certain</em> the Google JS had arrived. After various futile attempts, the solution ended up being pretty simple &#8211; change my</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span
style="color: #009900;">&#40;</span>document<span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">ready</span><span
style="color: #009900;">&#40;</span><span
style="color: #003366; font-weight: bold;">function</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span></div></td></tr></tbody></table></div><p>to</p><div
class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><table
cellspacing="0" cellpadding="0"><tbody><tr><td
style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br
/></div></td><td><div
class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span
style="color: #009900;">&#40;</span>window<span
style="color: #009900;">&#41;</span>.<span
style="color: #660066;">bind</span><span
style="color: #009900;">&#40;</span><span
style="color: #3366CC;">&quot;load&quot;</span><span
style="color: #339933;">,</span> <span
style="color: #003366; font-weight: bold;">function</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span></div></td></tr></tbody></table></div><p>That way, the bulk of my JS is only executed once everything else has loaded and sure enough, the issue disappeared!</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/02/google-maps-zoom-control-missing-in-internet-explorer-ie-a-solution/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Planned site downtime: how to handle it with PHP</title><link>http://www.drcoen.com/2011/01/planned-site-downtime-how-to-handle-it-with-php/</link> <comments>http://www.drcoen.com/2011/01/planned-site-downtime-how-to-handle-it-with-php/#comments</comments> <pubDate>Tue, 25 Jan 2011 22:56:17 +0000</pubDate> <dc:creator>David</dc:creator> <category><![CDATA[Code]]></category> <category><![CDATA[google]]></category> <category><![CDATA[php]]></category><guid
isPermaLink="false">http://www.drcoen.com/?p=53</guid> <description><![CDATA[Today I read an interesting article on Google&#8217;s Webmaster Central blog about planned down time, for maintenance or whatever. Basically, you need to communicate to users and potential site-crawlers/indexers that the site is down, but it&#8217;s ok, it&#8217;ll be back up soon! My suggestion would be to do a mod-rewrite (if using Apache, but other [...]]]></description> <content:encoded><![CDATA[<p>Today I read an interesting <a
href="http://googlewebmastercentral.blogspot.com/2011/01/how-to-deal-with-planned-site-downtime.html">article on Google&#8217;s Webmaster Central blog</a> about planned down time, for maintenance or whatever. Basically, you need to communicate to users and potential site-crawlers/indexers that the site is down, but it&#8217;s ok, it&#8217;ll be back up soon!</p><p>My suggestion would be to do a mod-rewrite (if using Apache, but other web servers have equivalents) on all incoming files to your 503 file, something like</p><div
class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;"><div
class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RewriteRule ^(.*)$ 503.php [L]</div></div><p>If you put this rule first, you can leave the rest of your rules where they are as the &#8220;L&#8221; at the end of the line tells Apache that this is the last rule it needs to process, i.e. it can ignore the others.</p><p>Then, in your <code>503.php</code> you need to tell any web-crawlers/site-indexers that the service is down but will be back at a certain time using PHP&#8217;s <code>header</code> function, as well as telling your users the same using a plain simple descriptive paragraph:</p><div
class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:600px;height:300px;"><div
class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span
style="color: #000000; font-weight: bold;">&lt;?php</span><br
/> <br
/> <span
style="color: #000088;">$back</span> <span
style="color: #339933;">=</span> <span
style="color: #0000ff;">'Tue, 1 Feb 2011 12:00:00 GMT'</span><span
style="color: #339933;">;</span><br
/> <br
/> <span
style="color: #666666; font-style: italic;">// tell any web-crawlers</span><br
/> <span
style="color: #990000;">header</span><span
style="color: #009900;">&#40;</span><span
style="color: #0000ff;">'HTTP/1.1 503 Service Temporarily Unavailable'</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #990000;">header</span><span
style="color: #009900;">&#40;</span><span
style="color: #0000ff;">'Retry-After: '</span><span
style="color: #339933;">.</span><span
style="color: #000088;">$back</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <br
/> <span
style="color: #666666; font-style: italic;">// calculate time to wait for users (I assume here it'll only be a matter of hours)</span><br
/> <span
style="color: #000088;">$vals</span> <span
style="color: #339933;">=</span> <span
style="color: #990000;">array</span><span
style="color: #009900;">&#40;</span><span
style="color: #0000ff;">'hour'</span> <span
style="color: #339933;">=&gt;</span> <span
style="color: #cc66cc;">3600</span><span
style="color: #339933;">,</span> <span
style="color: #0000ff;">'minute'</span> <span
style="color: #339933;">=&gt;</span> <span
style="color: #cc66cc;">60</span><span
style="color: #339933;">,</span> <span
style="color: #0000ff;">'second'</span> <span
style="color: #339933;">=&gt;</span> <span
style="color: #cc66cc;">1</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #000088;">$back_in_seconds</span> <span
style="color: #339933;">=</span> <span
style="color: #990000;">strtotime</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$back</span><span
style="color: #009900;">&#41;</span> <span
style="color: #339933;">-</span> <span
style="color: #990000;">time</span><span
style="color: #009900;">&#40;</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #000088;">$back_text</span> <span
style="color: #339933;">=</span> <span
style="color: #0000ff;">''</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #b1b100;">foreach</span> <span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$vals</span> <span
style="color: #b1b100;">as</span> <span
style="color: #000088;">$key</span> <span
style="color: #339933;">=&gt;</span> <span
style="color: #000088;">$time</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; <span
style="color: #000088;">$cur_time</span> <span
style="color: #339933;">=</span> <span
style="color: #990000;">floor</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$back_in_seconds</span> <span
style="color: #339933;">/</span> <span
style="color: #000088;">$time</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; <span
style="color: #b1b100;">if</span> <span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$cur_time</span><span
style="color: #009900;">&#41;</span> <span
style="color: #009900;">&#123;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #000088;">$back_text</span> <span
style="color: #339933;">.=</span> <span
style="color: #000088;">$cur_time</span><span
style="color: #339933;">.</span><span
style="color: #0000ff;">' '</span><span
style="color: #339933;">.</span><span
style="color: #000088;">$key</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #b1b100;">if</span> <span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$cur_time</span> <span
style="color: #339933;">!=</span> <span
style="color: #cc66cc;">1</span><span
style="color: #009900;">&#41;</span> <span
style="color: #000088;">$back_text</span> <span
style="color: #339933;">.=</span> <span
style="color: #0000ff;">'s'</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #000088;">$back_text</span> <span
style="color: #339933;">.=</span> <span
style="color: #0000ff;">', '</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; &nbsp; &nbsp; <span
style="color: #000088;">$back_in_seconds</span> <span
style="color: #339933;">%=</span> <span
style="color: #000088;">$time</span><span
style="color: #339933;">;</span><br
/> &nbsp; &nbsp; <span
style="color: #009900;">&#125;</span><br
/> <span
style="color: #009900;">&#125;</span><br
/> <span
style="color: #000088;">$back_text</span> <span
style="color: #339933;">=</span> <span
style="color: #990000;">rtrim</span><span
style="color: #009900;">&#40;</span><span
style="color: #000088;">$back_text</span><span
style="color: #339933;">,</span> <span
style="color: #0000ff;">', '</span><span
style="color: #009900;">&#41;</span><span
style="color: #339933;">;</span><br
/> <span
style="color: #000000; font-weight: bold;">?&gt;</span><br
/> &lt;html&gt;<br
/> &nbsp; &nbsp;&lt;!- etc. --&gt;<br
/> &nbsp; &nbsp; &lt;body&gt;<br
/> &nbsp; &nbsp; &lt;p&gt;<br
/> &nbsp; &nbsp; &nbsp; &nbsp; We are currently undergoing scheduled downtime to upgrade the site. &lt;br /&gt;<br
/> &nbsp; &nbsp; &nbsp; &nbsp; We'll be back in <span
style="color: #000000; font-weight: bold;">&lt;?=</span> <span
style="color: #000088;">$back_text</span> <span
style="color: #000000; font-weight: bold;">?&gt;</span>. Thanks for your patience.<br
/> &nbsp; &nbsp; &lt;/p&gt;<br
/> &nbsp; &nbsp; &lt;!-- etc. --&gt;<br
/> &nbsp; &nbsp; &lt;/body&gt;<br
/> &lt;/html&gt;</div></div><p>Should all be pretty straight-forward, but it&#8217;s good to let people know that you know you&#8217;re down and when you expect to be back.</p> ]]></content:encoded> <wfw:commentRss>http://www.drcoen.com/2011/01/planned-site-downtime-how-to-handle-it-with-php/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: basic
Database Caching using disk: basic
Object Caching 1122/2143 objects using disk: basic

Served from: www.drcoen.com @ 2012-05-22 10:44:11 -->
