<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>use strict ;#)</title>
	
	<link>http://usestrict.net</link>
	<description>Vinny's Technical Corner</description>
	<lastBuildDate>Wed, 14 Jul 2010 20:21:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/UseStrict" /><feedburner:info uri="usestrict" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>-23.6027</geo:lat><geo:long>-46.6922 </geo:long><feedburner:emailServiceId>UseStrict</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Latest Job Postings</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/7JHGx1aDByw/</link>
		<comments>http://usestrict.net/2010/03/03/latest-job-postings/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 17:58:00 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Jobs]]></category>
		<category><![CDATA[canada]]></category>
		<category><![CDATA[excerpt]]></category>
		<category><![CDATA[Job]]></category>
		<category><![CDATA[job postings]]></category>
		<category><![CDATA[jobs page]]></category>
		<category><![CDATA[list]]></category>
		<category><![CDATA[num]]></category>
		<category><![CDATA[page]]></category>
		<category><![CDATA[Postings]]></category>
		<category><![CDATA[refresh]]></category>
		<category><![CDATA[VERY]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=971</guid>
		<description>Latest Job Postings from several sources in Canada</description>
			<content:encoded><![CDATA[<p>For all the job hunters out there in Canada, a list of the latest job postings from several sources.</p>
<p><strong>See the full list at my <a href="/jobs/" target="_self">Jobs!! page</a></strong></p>

<p>The list is updated VERY frequently, so feel free to either refresh the page often or subscribe at <a href="http://feeds.feedburner.com/usestrictjobs">http://feeds.feedburner.com/jobsbyusestrict</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/9XHxpccCt_hdUiJoSbBYkeppOE4/0/da"><img src="http://feedads.g.doubleclick.net/~a/9XHxpccCt_hdUiJoSbBYkeppOE4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/9XHxpccCt_hdUiJoSbBYkeppOE4/1/da"><img src="http://feedads.g.doubleclick.net/~a/9XHxpccCt_hdUiJoSbBYkeppOE4/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=7JHGx1aDByw:ECbaDx406uc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=7JHGx1aDByw:ECbaDx406uc:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=7JHGx1aDByw:ECbaDx406uc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=7JHGx1aDByw:ECbaDx406uc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=7JHGx1aDByw:ECbaDx406uc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=7JHGx1aDByw:ECbaDx406uc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=7JHGx1aDByw:ECbaDx406uc:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/7JHGx1aDByw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2010/03/03/latest-job-postings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://usestrict.net/2010/03/03/latest-job-postings/</feedburner:origLink></item>
		<item>
		<title>I’m now on Suite101.com!</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/LK2HsIgg8hM/</link>
		<comments>http://usestrict.net/2009/09/22/im-now-on-suite101com/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 21:58:23 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=874</guid>
		<description>Hey folks! I'd like to announce that I've debuted on suite101.com. My first article there was how to optimize your job hunting using RSS feeds. Check out the article here.</description>
			<content:encoded><![CDATA[<p>Hey folks!</p>
<p>I'd like to announce that I've debuted on suite101.com. My first article there was how to optimize your job hunting using RSS feeds. </p>
<p><a href="http://job-search.suite101.com/article.cfm/optimize_your_search_for_new_jobs" target="_blank">Check out the article here.</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/SMYaS6AVARJ-lXOOttkr6Qk7Qqc/0/da"><img src="http://feedads.g.doubleclick.net/~a/SMYaS6AVARJ-lXOOttkr6Qk7Qqc/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/SMYaS6AVARJ-lXOOttkr6Qk7Qqc/1/da"><img src="http://feedads.g.doubleclick.net/~a/SMYaS6AVARJ-lXOOttkr6Qk7Qqc/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=LK2HsIgg8hM:AdneD-4oook:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=LK2HsIgg8hM:AdneD-4oook:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=LK2HsIgg8hM:AdneD-4oook:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=LK2HsIgg8hM:AdneD-4oook:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=LK2HsIgg8hM:AdneD-4oook:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=LK2HsIgg8hM:AdneD-4oook:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=LK2HsIgg8hM:AdneD-4oook:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/LK2HsIgg8hM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/09/22/im-now-on-suite101com/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/09/22/im-now-on-suite101com/</feedburner:origLink></item>
		<item>
		<title>Introduction to Ajax</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/aZP9Gmh-TiU/</link>
		<comments>http://usestrict.net/2009/08/24/introduction-to-ajax/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 21:56:08 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[how to]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=840</guid>
		<description>Introduction to Ajax, Ajax how-to</description>
			<content:encoded><![CDATA[<p>In this article, I provide an explanation of Ajax with a historical introduction. If you are eager to start seeing the code, please scroll down.</p>
<p>&nbsp;</p>
<h3>What’s Ajax?</h3>
<p>&nbsp;</p>
<p>Ajax stands for <em>Asynchronous Javascript And XML</em>. It’s a way to call back-end scripts asynchronously – that is, without impacting user experience/flow. Basically, you don't even see the cursor become an hourglass or whatever other "waiting/processing" icon your system uses. It's not a language, but a technique. As for back-end scripts, you can use whatever you feel more comfortable with: PHP, Perl, Java, JSP, Shell, C, etc. The way to choose which technology to use as back-end is not outside the scope of this article.</p>
<p>&nbsp;</p>
<h3>Historical approach for calling back-end apps</h3>
<p>&nbsp;</p>
<p>Throughout web-development history, the very first way used to achieve back-end processing followed by front-end display was to create a form and set the back-end script as the action to that form. Upon submission, the form fields would be sent to the back-end script as a series of special environment variables, which would then be handled by the programmed logic. The back-end output would be displayed on the screen (either the same page/frame or a different page/frame, depending on the target attribute of the form).</p>
<p>The catch 22 of this approach is that if you want to present another form after processing, that form must be produced by the back-end script, which leads to maintenance mayhem – to add or remove a field, you have to do so in both the original HTML and in the HTML of the back-end script.</p>
<p><span id="more-840"></span></p>
<p>&nbsp;</p>
<h3>Hidden IFRAMES and Javascript to the rescue</h3>
<p>&nbsp;</p>
<p>The natural evolution of the regular form submission was to avoid having to generate HTML from the back-end script. A technique that I eventually came up with (had never seen it before, but it was probably already out there) prior to adhering to Ajax was using a hidden IFRAME as target to a simple form containing an <em>action_cd</em> field and a <em>data</em> field. There would not be a regular submit button, but a set of input elements with <em>onclick</em> or <em>onchange</em> events and a regular (non-submit) button at the end. </p>
<p>In this approach, Javascript did all the work – when the user clicked the pseudo-submit button, an <em>onclick</em> event would read all the input fields and join them like a regular HTTP query (<code>field1=val1&#038;field2=val2</code>…). The <em>action_cd</em> value would be dynamically evaluated and the back-end script would receive the data string and action code and process it. Javascript would perform the submission when, say, a value of a drop-down field was selected, and the output would be a series of dynamically generated Javascript commands inside the IFRAME. Those commands would manipulate the user’s form (e.g. Auto-populate a "state" drop-down after selecting a "country" value). </p>
<p>Although this approach successfully handled the no-longer-need to submit and reload a form, it still had 2 main downsides: generating and maintaining Javascript code is not a simple task (especially due to having to escape quotes), and the whole procedure was still synchronous – you could see the hourglass, browser process bars, clicking sounds (IE), etc. It's much better user experience, but still not the real deal, seamless/transparent back-end processing.</p>
<p>&nbsp;</p>
<h3>The XmlHttpRequest object</h3>
<p>&nbsp;</p>
<p>Javascript back-end calls are made possible thanks to the <em>XmlHttpRequest</em> object that most modern browsers now support. For IE 6 and older, it is done through an ActiveXObject. </p>
<p>&nbsp;</p>
<h3>Javascript code to initialize Ajax object</h3>
<p>&nbsp;</p>
<pre class="brush:javascript">

var xmlHttp; // global variable. It’s important for later on

function GetXmlHttpObject(){

      if (window.XMLHttpRequest){
        // code for IE7+, Firefox, Chrome, Opera, Safari
        return new XMLHttpRequest();
      }

      if (window.ActiveXObject){
        // code for IE6, IE5
        return new ActiveXObject("Microsoft.XMLHTTP");
      }
      return null;
}
</pre>
<p>It's important to have a global variable in which to assign the XMLHttpRequest object, since this technique has its shortcomings when dealing with passing variables around. We'll understand that better shortly. The function checks for the existence of <strong>window.XMLHttpRequest</strong> which is used in IE7 (finally, it complies to standards!), Firefox, and other non IE browsers, and checks for <strong>window.ActiveXObject</strong> existence for IE6 and 5. I’m not sure if this works on IE4 – it probably does not, but hopefully IE4 is already in extinction. If neither checks work, it returns null, which will be handled in the function calling the XMLHttpObject.</p>
<p>&nbsp;</p>
<h3>Making Synchronous Ajax calls (GET method)</h3>
<p>&nbsp;</p>
<p>Although the hype of Ajax is due to the "Asynchronosity" of the technique, it is also capable of making synchronous calls. Synchronous calls are important in cases where you don't want to allow the user to do something while the back-end is checking a previous action, but also don't want to have to submit the whole form.</p>
<pre class="brush:javascript">

function synch_call() {

      // initialize Ajax object
      var xmlHttp = GetXmlHttpObject(); 

      // Set the URL to your backend script with query vars
      var url = “/url/to/your/backend/script?with=var1&#038;and=var2”;

      // Synchronous call
      xmlHttp.open("GET",url,false); // "false" means asynchronous = false
      xmlHttp.send(null);

      // the code above does the back-end call. Now we handle the response
      // this function continues further down in the tutorial

}
</pre>
<p>Ajax calls can be done using GET or POST methods. I recommend GET methods for small queries, POST for large ones. There used to be a limit of 255 characters on URL fields – not sure if a) this is still true; b) this could apply to these Ajax techniques.</p>
<p>The call to the back-end is done by 2 commands: <strong>xmlHttp.open(Method,url,async)</strong>, and the <strong>xmlHttp.send(null)</strong> calls. For POST method, this is a little different, so we’ll stick to GET calls for the time being.</p>
<p>&nbsp;</p>
<h3>Handling back-end reply</h3>
<p>&nbsp;</p>
<p><em>Asynchronous Javascript And XML</em> isn't the perfect name for Ajax. It should be more like Aja<strong>R</strong>, where R stands for Reply. The reason is because the reply can be either an XML structure or a plain text. We use <strong>xmlHttp.responseXML.documentElement</strong> if we’re handling XML, or a plain <strong>xmlHttp.responseText</strong> for plain text. Actually, we can use the latter for XML as well, especially when debugging the code (when you want to pop up the XML reply).</p>
<p>We use a try/catch block to capture any errors:</p>
<pre class="brush:javascript">
function synch_call() {

      // initialize Ajax object
      var xmlHttp = GetXmlHttpObject(); 

      // Set the URL to your backend script with query vars
      var url = “/url/to/your/backend/script?with=var1&#038;and=var2”;

      // Synchronous call

      xmlHttp.open("GET",url,false); // “false” means asynchronous = false
      xmlHttp.send(null);

      // the code above does the back-end call. Now we handle the response
      try {            

            alert("Ajax Response: \n"+xmlHttp.responseText); // Just pop-up the reply
            return false;
      }
      catch(e) {
            alert(e); // if error, show it as a pop-up
            return false;
      }
}
</pre>
<p>&nbsp;</p>
<p>To handle the  reply as XML, you need to a) make sure your back-end script outputs an XML structure, and b), replace xmlHttp.reponseText for xmlHttp.responseXML.documentElement.</p>
<p>&nbsp;</p>
<pre class="brush:javascript">
// Just the try/catch block changed        

       try {
              data = xmlHttp.responseXML.documentElement;
        }
        catch(e) {
               alert(e);
               return false;
        }
</pre>
<p>The <code>data</code> variable now holds a DOM object of the XML structure. To access its elements, we use DOM functions. </p>
<p>Example XML structure:</p>
<pre class="brush:xml">
&lt;OUT&gt;
      &lt;STATUS&gt;Success&lt;/STATUS&gt;
      &lt;MSG type="some_type"&gt;This is a test message&lt;/MSG&gt;
&lt;/OUT&gt;
</pre>
<p>Accessing Example XML through DOM:</p>
<pre class="brush:javascript">

      // gets the Success text
      var msg_status = data.getElementsByTagName(‘STATUS’)[0].childNodes[0].nodeValue;

      // Assign MSG object to msg variable
      var msg = data.getElementsByTagName(‘MSG’)[0]; 

      // gets the attribute “type”
      var msg_type = msg.getAttribute(‘type’); 

      // gets the text inside the MSG node
      var msg_text = msg.childNodes[0].nodeValue;
</pre>
<p>&nbsp;</p>
<h3>Putting it all together</h3>
<p>&nbsp;</p>
<pre class="brush:javascript">
function synch_call() {

      // initialize Ajax object
      var xmlHttp = GetXmlHttpObject(); 

      // Set the URL to your backend script with query vars
      var url = “/url/to/your/backend/script?with=var1&#038;and=var2”; 

      // Synchronous call
      xmlHttp.open("GET",url,false); // "false" means asynchronous = false
      xmlHttp.send(null);

      // the code above does the back-end call. Now we handle the response

      try {
            data = xmlHttp.responseXML.documentElement;
       }
       catch(e) {
             alert(e);
             return false;
       }

      // gets the Success text
      var msg_status = data.getElementsByTagName(‘STATUS’)[0].childNodes[0].nodeValue; 

      // Assign MSG object to msg variable
      var msg = data.getElementsByTagName(‘MSG’)[0]; 

      // gets the attribute “type”
      var msg_type = msg.getAttribute(‘type’); 

      // gets the text inside the MSG node
      var msg_text = msg.childNodes[0].nodeValue;
      alert("Got the following backend reply: " + msg_status + "\n" + msg + "\n" + msg_type + "\n" + msg_text);

      return true;
}
</pre>
<p>&nbsp;</p>
<h3>Making Asynchronous Ajax calls (GET method)</h3>
<p>&nbsp;</p>
<p>We saw on page 2 that what controls synchronicity of the Ajax call is the true/false value in the <code>open()</code> command. However, we also need changes in the way we handle the reply. We do that by setting <strong><em>onreadystatechange</em></strong> property on the xmlHttp object.</p>
<p> OnReadyStateChange should be a function that will check the <em><strong>readyState</strong></em> attribute of the xmlHttp object.</p>
<p>&nbsp;</p>
<h3>Understanding readyState</h3>
<p>&nbsp;</p>
<p>readyStates are the way Javascript controls what stage of the process the call is in. It ranges from 0 to 4, where 4 is the completed reply from the back-end script. We normally only care about readyState == 4. Here are the codes and meaning:</p>
<table>
<tr>
<td><strong>Value</strong></td>
<td><strong>State</strong></td>
</tr>
<tr>
<td>0</td>
<td>Uninitialized</td>
</tr>
<tr>
<td>1</td>
<td>Loading</td>
</tr>
<tr>
<td>2</td>
<td>Loaded</td>
</tr>
<tr>
<td>3</td>
<td>Interactive</td>
</tr>
<tr>
<td>4</td>
<td>Complete</td>
</tr>
</table>
<p>&nbsp;</p>
<h3>Setting onreadystatechange</h3>
<p>&nbsp;</p>
<p><code>onreadystatechange</code> can be assigned a anonymous <code>function() {  }</code> block, or a named function. Just be careful with function parameters – to this day, I have not been able to pass any parameters to the functions set to <code>onreadystatechange</code>. Hence the need for some global variables in play.</p>
<p>Let's copy over our <code>sync_call()</code> function and make it <code>Async_call()</code></p>
<pre class="brush:javascript">
function Asynch_call() {

      // initialize Ajax object
      var xmlHttp = GetXmlHttpObject(); 

      // Set the URL to your backend script with query vars
      var url = “/url/to/your/backend/script?with=var1&#038;and=var2”;

      // onreadystatechange must be set BEFORE making the call

      // it takes the response handling code that we had in the sync_call() previously
      xmlHttp.onreadystatechange = function() {

            if (xmlHttp.readyState == 4) { // Complete

                  // Now we handle the response within the onreadystatechange
                  try {
                        data = xmlHttp.responseXML.documentElement;
                  }
                  catch(e) {
                        alert(e);
                        return false;
                  }

                  // gets the Success text
                  var msg_status = data.getElementsByTagName(‘STATUS’)[0].childNodes[0].nodeValue; 

                  // Assign MSG object to msg variable
                  var msg = data.getElementsByTagName(‘MSG’)[0]; 

                  // gets the attribute "type"
                  var msg_type = msg.getAttribute('type'); 

                  // gets the text inside the MSG node
                  var msg_text = msg.childNodes[0].nodeValue;

                  alert("Got the following backend reply: " + msg_status + "\n" + msg + "\n" + msg_type + "\n" + msg_text);
                  return true;
            }

      }; // don’t forget the ';' at the end of the function() {} block!!

      // Asynchronous call
      xmlHttp.open("GET",url,true); // 'true' means asynchronous = true
      xmlHttp.send(null);
}
</pre>
<p>&nbsp;</p>
<p>As mentioned before, you can separate the anonymous function assignment into a named function. The good side of this is that your functions get more manageable, but the downside is that you might need global variables in order to share values between the main function and the <code>onreadystatechange,/code> function.</p>
<p>&nbsp;</p>
<pre class="brush:javascript">
function Asynch_call() {

      // initialize Ajax object
      var xmlHttp = GetXmlHttpObject(); 

      // Set the URL to your backend script with query vars
      var url = “/url/to/your/backend/script?with=var1&#038;and=var2”; 

      // onreadystatechange must be set BEFORE making the call

      // it takes the response handling code that we had in the sync_call previously
      xmlHttp.onreadystatechange = handlerfunction; // See separate function below    

      // Asynchronous call
      xmlHttp.open("GET",url,true); // “true” means asynchronous = true
      xmlHttp.send(null);
}

function handlerfunction() {

      if (xmlHttp.readyState == 4) { // Complete – must be global xmlHttp variable

            // Now we handle the response within the onreadystatechange
            try {
                  data = xmlHttp.responseXML.documentElement;
            }
            catch(e) {
                  alert(e);
                  return false;
            }

             // gets the Success text
            var msg_status = data.getElementsByTagName(‘STATUS’)[0].childNodes[0].nodeValue; 

            // Assign MSG object to msg variable
            var msg = data.getElementsByTagName(‘MSG’)[0]; 

            // gets the attribute “type”
            var msg_type = msg.getAttribute(‘type’); 

            // gets the text inside the MSG node
            var msg_text = msg.childNodes[0].nodeValue;

            alert("Got the following back-end reply: " + msg_status + "\n" + msg + "\n" + msg_type + "\n" + msg_text);
            return true;

      }
}
</pre>
<p>&nbsp;</p>
<h3>Parsing forms to create the GET/POST strings</h3>
<p>&nbsp;</p>
<p>Since we are not submitting the form with the usual submit button, we have to handle building the queries ourselves. I came up with a function that mimics the way browsers handle function calls.</p>
<pre class="brush:javascript">
function build_post_string(frm) {

      var str;
      var poststr_array = [];

      if (!frm.id) {
            // assume it's a string. get the form object
            frm = document.getElementById(frm);
      }

      for (i=0;i&lt;frm.elements.length;i++){

            var elem = frm.elements[i];

            if (!elem.id) {
                  // skip any fields that don't have IDs
                  continue;
            }

            if (elem.type == 'radio' || elem.type == 'checkbox') {

                  // only grab radio buttons and checkboxes that are checked
                  if (!elem.checked) {
                        continue;
                  }

            }            

            // get select values
            if (elem.nodeName.match(/SELECT/i) &#038;& elem.multiple) {

                  var sel_array = [];

                  for (var o=0;o&lt;elem.options.length;o++) {

                        if (elem.options[o].selected) {
                              sel_array[sel_array.length] = elem.id+"="+elem.options[o].value;
                        }

                  }

                  var sel_str = sel_array.join('&#038;');

                  // build key/value pairs for SELECTs
                  poststr_array[poststr_array.length] = sel_str;
            }
            else if (elem.nodeName.match(/SELECT/i)) {
                  poststr_array[poststr_array.length] = elem.id+'='+elem.options[elem.selectedIndex].value;
            }
            else {
                  // build key/value pairs for everything else
                  poststr_array[poststr_array.length] = elem.id+"="+elem.value;
            }

      }

      // build and return str
      str = poststr_array.join("&#038;");
      return str;
}
</pre>
<p>This function takes a given form by ID and iterates through all of its elements. It is important that all fields you want in the query have an ID attribute. Otherwise they will be skipped. <strong>The return from this function can be used for both GET and POST requests.</strong></p>
<p>&nbsp;</p>
<h3>Using POST method for Ajax calls</h3>
<p>&nbsp;</p>
<p>So far we saw that making GET calls is pretty straight-forward. POST calls are different in the way that they are not put in the HTTP Header, but rather in a separate packet. In order to do that, we need to set a few header variables:</p>
<pre class="brush:javascript">
function Asynch_call_with_post() {

      // initialize Ajax object
      var xmlHttp = GetXmlHttpObject(); 

      // Set the URL to your backend script with query vars
      var post_str = build_post_string(‘my_form’); 

      var url = “/url/to/your/backend/script?” + post_str;

      // onreadystatechange must be set BEFORE making the call
      // it takes the response handling code that we had in the sync_call previously
      xmlHttp.onreadystatechange = function() {

            if (xmlHttp.readyState == 4) { // Complete

                   // Now we handle the response within the onreadystatechange
                   try {
                         data = xmlHttp.responseXML.documentElement;
                    }
                    catch(e) {
                         alert(e);
                         return false;
                    }

                     // gets the Success text
                     var msg_status = data.getElementsByTagName(‘STATUS’)[0].childNodes[0].nodeValue; 

                      // Assign MSG object to msg variable
                     var msg = data.getElementsByTagName(‘MSG’)[0]; 

                     // gets the attribute “type”
                     var msg_type = msg.getAttribute(‘type’); 

                     // gets the text inside the MSG node
                     var msg_text = msg.childNodes[0].nodeValue;
                     alert("Got the following backend reply: " + msg_status + "\n" + msg + "\n" + msg_type + "\n" + msg_text);
                     return true;
               }

        }; // don't forget the ';' at the end of the function() {} block

        // Asynchronous call
        xmlHttp.open('POST',url, true); // Replace "GET" with "POST"

        // Set headers
        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlHttp.setRequestHeader("Content-length", url.length);
        xmlHttp.setRequestHeader("Connection", "close");

        // Send the packet. Note that it’s no longer null as parameter to send
        xmlHttp.send(url);
}
</pre>
<p>&nbsp;</p>
<h3>Showing/Hiding "Processing…" messages</h3>
<p>&nbsp;</p>
<p>Since Ajax in Asynchronous mode is 100% transparent to the user, it is necessary to handle our own messages asking the user to wait until processing finishes. The simplest way to do this is by using a <code>DIV</code> element with initial display property set as none, or visibility set as hidden (the difference is that <code>visibility="hidden"</code> makes the element still occupy its space in the page, whereas <code>display="none"</code> effectively removes the element from the page and the space that it occupied).</p>
<p>Typically, I include code to show the element in the Ajax function, and code to hide it again in the <em>onreadystatechange</em> function (where readyState == 4). </p>
<pre class="brush:javascript">
        document.getElementById(‘wait_image’).display = ‘block’;
        document.getElementById(‘wait_image’).display = ‘none’;
</pre>
<p>&nbsp;</p>
<h3>Third-Party AJAX Libraries</h3>
<p>&nbsp;</p>
<p>There are several Ajax in a box libraries out there, but I am not comfortable with using them for company applications. The reason being is that Ajax is very powerful and can very well make calls to the maintainer's website to steal/capture sensitive information.  </p>
<p>Google provides Java code that generates Ajax during build – that is a typical example of us not being able to control Ajax code generated. </p>
<p>&nbsp;</p>
<h3>Testing the back-end script</h3>
<p>&nbsp;</p>
<p>There are 2 simple ways of testing the back-end script. With PHP, you can access both GET and POST variables through the <code>$_REQUEST</code> array. Perl CGI doesn’t really care if it’s GET or POST. I don’t know how JSP can handle it. With this being said, I simply have the Ajax alert the URL variable and return false. I then copy the URL variable and paste it in another window to see the output.</p>
<p>I strongly recommend debugging with Firefox – it has a handy error console and also parses the output XML or complains if it’s not built right.</p>
<p>&nbsp;</p>
<h3>Keeping IE from crashing with the XMLs</h3>
<p>&nbsp;</p>
<p>I'm pretty sure that Microsoft IE developers have some satisfaction in making web developers go crazy. That's how I felt when I started working with XML and Ajax, and although my <a href="http://mywebchat.usestrict.net" target="_blank">app</a> was working fine in Firefox, it kept crashing bad in IE. After some googling, I found out that I needed to set some headers in order to keep IE from blowing up. I already had the <code>"Content-type: text/xml"</code> header in place, but it appears that IE needs some caching control and expiry headers as well.</p>
<p>This is what I use in PHP:</p>
<pre class="brush:php">
        header("Expires: Fri, 09 Jan 1981 05:00:00 GMT");
        header("Cache-Control: no-store, no-cache, must-revalidate");
        header("Cache-Control: post-check=0, pre-check=0", FALSE); // FALSE means add this Cache-Control line instead of replacing the previous one
        header("Pragma: no-cache");
        header("Content-type: text/xml");
</pre>
<p>In Perl, setting headers is simple: just <code>print</code> them before printing any content. When you're done printing all your headers, print an empty newline to indicate where the page content will go.</p>
<p>I hope you've enjoyed this tutorial. Feel free to paste comments regarding your experience and preferences.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/b6icL9UU_xHV92gHp5uiJMvJqNU/0/da"><img src="http://feedads.g.doubleclick.net/~a/b6icL9UU_xHV92gHp5uiJMvJqNU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/b6icL9UU_xHV92gHp5uiJMvJqNU/1/da"><img src="http://feedads.g.doubleclick.net/~a/b6icL9UU_xHV92gHp5uiJMvJqNU/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=aZP9Gmh-TiU:-CmOghY6yaw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=aZP9Gmh-TiU:-CmOghY6yaw:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=aZP9Gmh-TiU:-CmOghY6yaw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=aZP9Gmh-TiU:-CmOghY6yaw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=aZP9Gmh-TiU:-CmOghY6yaw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=aZP9Gmh-TiU:-CmOghY6yaw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=aZP9Gmh-TiU:-CmOghY6yaw:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/aZP9Gmh-TiU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/08/24/introduction-to-ajax/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/08/24/introduction-to-ajax/</feedburner:origLink></item>
		<item>
		<title>PHP+PDO+MySQL: How I’m doing it and a question…</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/0fy_BTPubKU/</link>
		<comments>http://usestrict.net/2009/08/13/phppdomysql-how-im-doing-it-and-a-question/#comments</comments>
		<pubDate>Thu, 13 Aug 2009 12:47:18 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PDO]]></category>
		<category><![CDATA[Select]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Update]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=832</guid>
		<description>Example of PHP+PDO+MySQL usage to select and update arbitrary fields. Only one prepared statement is used for updating the data.</description>
			<content:encoded><![CDATA[<p>I recently decided to rewrite an application that I created for an English school where I used to work, and this time I want to do it right. I chose to write it in PHP with Object Orientation in mind, and use PDO+MySQL for the DAO portion.</p>
<p>The reason for using PDO is that it's the closest thing to the DBI that I found for PHP - and the reason for PHP is that it's just plain simpler than using pure Perl, and I don't have the time to learn Catalyst or some other Perl Web framework.</p>
<p>Anyway, here's what I'm doing for the PDO portion.</p>
<p>First I created a <code>Db</code> class which is just a DB connection wrapper.</p>
<pre class="brush:php">
&lt;?php
class Db{

	public $dbh  = null;

	public function Db($db_type,$db_host,$db_user,
			         $db_pass,$db_base,$tbl_prefix){

		if ($db_type == 'mysql') { // in case I want to add oracle in the future

			$mysql_DSN = "mysql:host=".$db_host.";dbname=".$this->db_base;

			try {
				$this->dbh = new PDO($mysql_DSN, $db_user, $db_pass,
							   array(PDO::ATTR_PERSISTENT => true, PDO::ERRMODE_WARNING => true,
							         PDO::ATTR_ERRMODE => true));

			}
			catch(PDOException $e){
				$rc[msg] = $e->getMessage();
				die($rc[msg] . "  " . __LINE__);
			}

			return $this->dbh;

		}

	}

}
?&gt;
</pre>
<p>Secondly, I created the DAO classes which extend the DB. They are responsible for <code>prepare</code>'ing and <code>execute</code>'ing the queries, and returning the data. Here's an example one (I stripped some bells and whistles in order to not confuse anyone):</p>
<pre class="brush:php">
&lt;?php
class StudentsDao extends Db {

	public $sth = array();

	// Constructor
	public function StudentsDao($db_type=NULL,$db_host=NULL,$db_user=NULL,
				  	       $db_pass=NULL,$db_base=NULL,$tbl_prefix=NULL) { // These params are to be passed to Db class

		// Connect to DB
		$this->Db($db_type,$db_host,$db_user,
			      $db_pass,$db_base,$tbl_prefix);

		// Prepares queries
		$this->sth = $this->prepare($tbl_prefix); // Look at prepare() further down

	} // end of function StudentsDao

	// Function that prepares queries
	public function prepare() {

		$sth = null; // will hold our temporary array

		// get all students
		$string = sprintf('select * from %s.%sstudents where id = ?',DB_BASE,TBL_PREFIX);	// I have these constants defined in the main page
		$sth['getStudentById'] = $this->dbh->prepare($string);

		// update Student by Id
		$string = sprintf('update %s.%sstudents
				   set field1 = ?, field2 = ?, field3 = ?
				   where id = ?',DB_BASE,TBL_PREFIX);	// Note that this table has 3 control fields (id, sys_creation_date, and sys_update_date)  prior to field1, field2, and field3 - I don't want them to be touched

		$sth['updStudentById'] = $this->dbh->prepare($string);

		return $sth;

	} // end of prepare()

	// Here we have the handlers for the queries prepared above.

	// Fetches all students
	public function getStudentById($id) {

		$s = $this->sth['getStudents'];
		$s->execute(array($id)) || die(print_r($s->errorInfo,1));
		$result = $s->fetchAll(PDO::FETCH_ASSOC);

		if (sizeof($result) == 0) {
			// no data found
			$out[err_cd] = 1;
		}
		else {
			// data was found
			$out[err_cd] = 0;
			$out[data] = $result;
		}

		return $out;

	}

	// Updates student by Id - this is a tricky one
	public function updateStudentById($data,$id){ // $data can have data regarding one or more fields

		// Populate current fields
		$fields = $this->getStudentById($id); // get current values

		// Remove unwanted fields
		$fields = array_slice($fields[data][0],3); // remove the 3 initial control fields

		// Replace with new fields
		foreach($data as $k=>$v){
			$fields[strtolower($k)] = $v;
		}
		$fields['id'] = $id;

		$s = $this->sth['updStudentById'];
		$s->execute(array_values($fields)) || die(print_r($s->errorInfo,1));
		$count = $s->rowCount();

		if ($count == 1) {
			$out[err_cd] = 0;
		}
		else {
			$out[err_cd] = -1;
		}
		$out[err_msg] = $this->status[$out[err_cd]];
		return $out;

	}
?&gt;
</pre>
<p>In the example above, you will probably frown on the fact that I'm calling <code>getStudentById()</code> at the beginning of <code>updateStudentById()</code>. It's OK - I frown on it, too. Let me explain why I did that:</p>
<p>I wanted to be able to pass the function an associative array containing only the fields I want to update - be it only <code>field1</code>, or <code>field1</code> and <code>field2</code> and so on. But I wanted to do that against my already prepared query, and not touching any additional fields. In my application, <code>students</code> table has a BUNCH of fields. In other words, update any given field or set of fields using the single prepared statement, <strong>without</strong> having to set ALL the fields in <code>$data</code></p>
<p>My original idea was to basically, to emulate something like this:</p>
<p><code> update students set field1=field1, field2='some new value ', field3=field3 where id = 1</code></p>
<p>That would set <code>field1</code> to whatever value <code>field1</code> already had. </p>
<p><strong>Here's the question part:<br />
Unfortunately, I couldn't figure out how to do that using the PDO (how to bind a field name instead of a value against the <code>?</code>-mark). If you know how to do that, do leave a comment explaining how! <img src='http://usestrict.net/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /><br />
</strong></p>
<p>The technique shown in the example will basically pull all values from the record and populate them in the <code>$fields</code> array. The <code>array_slice()</code> is used to remove the control fields that I have in my table, and the rest gets compared against the <code>$data</code> array and if any matching fields are found in <code>$data</code>, those fields get their values assigned over the existing <code>$fields</code> values.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/5jGPqFscLD-uYPWd9gWYb47S35I/0/da"><img src="http://feedads.g.doubleclick.net/~a/5jGPqFscLD-uYPWd9gWYb47S35I/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/5jGPqFscLD-uYPWd9gWYb47S35I/1/da"><img src="http://feedads.g.doubleclick.net/~a/5jGPqFscLD-uYPWd9gWYb47S35I/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=0fy_BTPubKU:wh8hLnP6_Hc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=0fy_BTPubKU:wh8hLnP6_Hc:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=0fy_BTPubKU:wh8hLnP6_Hc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=0fy_BTPubKU:wh8hLnP6_Hc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=0fy_BTPubKU:wh8hLnP6_Hc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=0fy_BTPubKU:wh8hLnP6_Hc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=0fy_BTPubKU:wh8hLnP6_Hc:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/0fy_BTPubKU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/08/13/phppdomysql-how-im-doing-it-and-a-question/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/08/13/phppdomysql-how-im-doing-it-and-a-question/</feedburner:origLink></item>
		<item>
		<title>Ajax: Form fields into URL query string</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/kMzUelMiFio/</link>
		<comments>http://usestrict.net/2009/07/31/ajax-form-fields-into-url-query-string/#comments</comments>
		<pubDate>Fri, 31 Jul 2009 09:46:20 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Query string]]></category>
		<category><![CDATA[URL Query]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=818</guid>
		<description>Javascript code to parse form fields into URL query string. To be used with Ajax sites.</description>
			<content:encoded><![CDATA[<p>Here's a quickie for you Ajax coders who need a function to parse your form fields into a URL query string. It handles input fields (text, hidden, whatever), radio and checkbox elements, and single/multiple select menus. Just make sure that all your form fields have IDs. <del>Multiple choice SELECTs get grouped by pipes (|).</del> <strong>Update:</strong>Modified multiple-choice SELECTs to work like real GETs.</p>
<pre class="brush:javascript">
function build_post_string(frm) {

	var poststr;
	var poststr_array = [];

	if (!frm.id) {
		// assume it's a string. get the form object
		frm = document.getElementById(frm);
	}

	for (i=0;i&lt;frm.elements.length;i++){

		var elem = frm.elements[i];

		if (!elem.id) {
			// skip any fields that don't have IDs
			continue;
		}

		if (elem.type == 'radio' || elem.type == 'checkbox') {
			// only grab radio buttons and checkboxes that are checked
			if (!elem.checked) {
				continue;
			}
		}

		// get select values
		if (elem.nodeName.match(/SELECT/i) &#038;& elem.multiple) {
			//var sel = elem;
			var sel_array = new Array();

			for (var o=0;o&lt;elem.options.length;o++) {

				if (elem.options[o].selected) {
					sel_array[sel_array.length] = elem.id+"="+elem.options[o].value;
				}
			}

			var sel_str = sel_array.join('&#038;');

			// build key/value pairs for SELECTs
			poststr_array[poststr_array.length] = sel_str;
		}
		else if (elem.nodeName.match(/SELECT/i)) {
			poststr_array[poststr_array.length] = elem.id+'='+elem.options[elem.selectedIndex].value;
		}
		else {
			// build key/value pairs for everything else
			poststr_array[poststr_array.length] = elem.id+"="+elem.value;
		}

	}

	// build poststr
	poststr = poststr_array.join("&#038;");
	return poststr;

}
</pre>

<p><a href="http://feedads.g.doubleclick.net/~a/RPTSM4FIBg_pp4BfGEhwVHIz0bE/0/da"><img src="http://feedads.g.doubleclick.net/~a/RPTSM4FIBg_pp4BfGEhwVHIz0bE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/RPTSM4FIBg_pp4BfGEhwVHIz0bE/1/da"><img src="http://feedads.g.doubleclick.net/~a/RPTSM4FIBg_pp4BfGEhwVHIz0bE/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=kMzUelMiFio:7hiD6DBgPWo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=kMzUelMiFio:7hiD6DBgPWo:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=kMzUelMiFio:7hiD6DBgPWo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=kMzUelMiFio:7hiD6DBgPWo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=kMzUelMiFio:7hiD6DBgPWo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=kMzUelMiFio:7hiD6DBgPWo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=kMzUelMiFio:7hiD6DBgPWo:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/kMzUelMiFio" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/07/31/ajax-form-fields-into-url-query-string/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/07/31/ajax-form-fields-into-url-query-string/</feedburner:origLink></item>
		<item>
		<title>Perl: Installing DBD::Oracle + Oracle Instant Client on Ubuntu 9.04</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/6PI9YmkLe7U/</link>
		<comments>http://usestrict.net/2009/07/12/perl-installing-dbdoracle-on-ubuntu-904-and-oracle-instant-client/#comments</comments>
		<pubDate>Sun, 12 Jul 2009 16:17:20 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Accept]]></category>
		<category><![CDATA[article material]]></category>
		<category><![CDATA[course]]></category>
		<category><![CDATA[CPAN]]></category>
		<category><![CDATA[dbd]]></category>
		<category><![CDATA[dbd::oracle]]></category>
		<category><![CDATA[dbi]]></category>
		<category><![CDATA[distro]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[dpkg]]></category>
		<category><![CDATA[everything]]></category>
		<category><![CDATA[file]]></category>
		<category><![CDATA[gazillion times]]></category>
		<category><![CDATA[home directory]]></category>
		<category><![CDATA[Install]]></category>
		<category><![CDATA[Instant]]></category>
		<category><![CDATA[laptop]]></category>
		<category><![CDATA[LIBRARY]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[nbsp]]></category>
		<category><![CDATA[oracle db]]></category>
		<category><![CDATA[oracle distribution]]></category>
		<category><![CDATA[Oracle Instant Client]]></category>
		<category><![CDATA[perl 5]]></category>
		<category><![CDATA[perl mcpan]]></category>
		<category><![CDATA[pre requisites]]></category>
		<category><![CDATA[root]]></category>
		<category><![CDATA[root password]]></category>
		<category><![CDATA[rpm]]></category>
		<category><![CDATA[Set]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[Site]]></category>
		<category><![CDATA[sudo]]></category>
		<category><![CDATA[surprise]]></category>
		<category><![CDATA[time]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[using oracle]]></category>
		<category><![CDATA[VirtualBox]]></category>
		<category><![CDATA[Windows XP]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=789</guid>
		<description>Easy to follow steps on how to install DBD::Oracle using Oracle Instant Client on Ubuntu 9.04</description>
			<content:encoded><![CDATA[<p>A couple of weeks ago I finally got a new laptop at work - which meant of course that I had to reinstall everything. Although we use Windows XP, there's one app that I have to run through Linux. The solution was <a href="http://www.virtualbox.org/" target="_blank">Sun's VirtualBox</a> running <a href="http://www.ubuntu.com/" target="_blank">Ubuntu 9.04</a>. When I tried to run the app, I realized that I still needed to install DBI and DBD::Oracle - which brings me to this article. Nothing better than a reinstall to generate article material <img src='http://usestrict.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>DBD::Oracle is usually a pain to install if you haven't already done it a gazillion times. After that, it's just an annoying itch. In this article I'll cover installing DBD::Oracle using Oracle Instant Client, Ubuntu 9.04, and Perl 5.10. Since we're using the Instant Client, you'll need some Oracle DB you can connect to in order to do the testing. You can choose to skip testing altogether, but you might be into a surprise later.<span id="more-789"></span></p>
<p>&nbsp;</p>
<h2>DBI and DBD::Oracle</h2>
<p>Installing the <strong>DBI</strong> is always easy - regardless if you're running Windows or Linux. Just follow the steps.</p>
<ol>
<li>Get root password if you don't already have one: <code><strong><em>sudo passwd root</em></strong></code></li>
<li>Switch to root: <code><strong><em>su -</em></strong></code>
<li>Run CPAN: <code></strong><em>perl -MCPAN -e shell</em></strong></code></li>
<li>Check if DBI is already installed: <code><strong><em>m DBI</em></strong></code></li>
<li>If it's not installed, install it: <code><strong><em>install DBI</em></strong></code></li>
</ol>
<p>That should do the trick for the DBI. The DBD::Oracle is a bit more complicated and we'll just use CPAN to download it for us. The rest is manual.</p>
<ol>
<li>Check for DBD::Oracle: <code><strong><em>m DBD::Oracle</em></strong></code></li>
<li>Download it: <code><strong><em>get DBD::Oracle</em></strong></code></li>
<li>Exit CPAN: <code><strong><em>q</em></strong></code></li>
</ol>
<p>Now we should have the DBD::Oracle distribution downloaded to our CPAN build directory. If you don't know where to find it, look for <code>.cpan</code> dir under your root home or (if you started CPAN for the first time doing <code>sudo</code> from your main user, look for it under your main user's home directory). We'll leave that distro aside for a moment and work on the other pre-requisites.</p>
<p>&nbsp;</p>
<h2>Oracle Instant Client</h2>
<p>Download the instant client packages you'll need. I chose to download the RPMs and convert them to .deb files using <code>alien</code>. Oracle also provides .zip files if you don't want to do it the <code>alien</code> way.</p>
<p><a href="http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/linuxsoft.html" target="_blank">Oracle Instant Client Download Site i386</a><br />
<a href="http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/linux-amd64.html" target="_blank">Oracle Instant Client Download Site AMD64 32- and 64-bit</a></p>
<p>Accept the license agreement by clicking the Accept radio button. Since the i386 and amd64 files have different names, check the bold words in the file names to know which ones to download (the names below are for the i386 platform). Also, if you don't have a user_id for Oracle, you'll be prompted to register one once you click the link. It's free of charge.</p>
<ul>
<li>oracle-instantclient11.1-<strong>basic</strong>-xx.x.x.x.x-x.i386.rpm</li>
<li>oracle-instantclient11.1-<strong>sqlplus</strong>-xx.x.x.x.x-x.i386.rpm</li>
<li>oracle-instantclient11.1-<strong>devel</strong>-xx.x.x.x.x-x.i386.rpm</li>
</ul>
<p>AMD64 has only zip files from what I could find, and they're named a bit differently, too (remove the <span style="color:red">32</span> for the 64-bit version:</p>
<ul>
<li>instantclient-<strong>basic</strong>-linuxAMD64-<span style="color:red">32</span>-xx.x.x.x.x-yyyymmdd.zip</li>
<li>instantclient-<strong>sqlplus</strong>-linuxAMD64-<span style="color:red">32</span>-xx.x.x.x.x-yyyymmdd.zip</li>
<li>instantclient-<strong>sdk</strong>-linuxAMD64-<span style="color:red">32</span>-xx.x.x.x.x-yyyymmdd.zip</li>
</ul>
<p><em>Note: Extract the zips into a directory called instantclient and skip to the <strong>Set Up your Environment Variables</strong> section if you're using the AMD64 or i386 zip files.</em></p>
<p>&nbsp;</p>
<p><center><script type="text/javascript"><!--
google_ad_client = "pub-3864472231411838";
google_ui_features = "rc:0";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text_image";
google_color_border = "{{color-border}}";
google_color_bg = "{{color-bg}}";
google_color_link = "{{color-title}}";
google_color_text = "{{color-text}}";
google_color_url = "{{color-link}}";

//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</center></p>
<p>&nbsp;</p>
<h2>Install alien and libaio</h2>
<p>Now is the time to install <code>alien</code>, which is an application that converts rpm files into .deb format to be used with <code>dpkg</code>. Instant Client also requires <code>libaio</code>. Both can be installed through the Synaptic Package Manager. Just open it, look for <code>alien</code>, mark it for install and do the same for <code>libaio</code> and <code>libaio-dev</code>. Once they're installed, you're good to move on to install the Instant Client. Just don't forget to exit Synaptic Package Manager, since we'll be using <code>dpkg</code> and it won't work if Synaptic is open.</p>
<p>&nbsp;</p>
<h2>Install Oracle Instant Client</h2>
<p>First step to install Oracle Instant Client from rpm files is to convert them into .deb files. Do that with <code>alien</code> by running the following command (from a command line in the directory where you downloaded your RPMs):</p>
<p><code>$ sudo alien --scripts *.rpm</code></p>
<p>It takes a little while to run, so be patient. Once it's complete, install the newly created .deb files: </p>
<p><code>$ dpkg -i *.deb</code></p>
<p>&nbsp;</p>
<h2>Set up your Environment Variables</h2>
<p>The nasty thing about rpm files is that it's not always easy to know where the files were installed. If you opted for the zip file approach, your install will most definitely be different. For RPM install, add this to your <code>.bashrc</code> file (swap xx.x for your oracle version):</p>
<p><code><br />
export ORACLE_HOME=/usr/lib/oracle/xx.x/client<br />
export PATH=$PATH:$ORACLE_HOME/bin<br />
export LD_LIBRARY_PATH=$ORACLE_HOME/lib<br />
</code></p>
<p><strong>Update:</strong> If you get an ELFCLASS64 error, try setting LD_LIBRARY_PATH to $ORACLE_HOME/lib32 instead. </p>
<p>Reload your <code>.bashrc</code> file:<br />
<code>$. ~/.bashrc</code></p>
<p>Note: by default, Oracle Instant Client doesn't come with a <code>tnsnames.ora</code> file or the directory structure where it's usually found. We'll have to create that ourselves - </p>
<p><code>$ mkdir -p $ORACLE_HOME/network/admin; touch $ORACLE_HOME/network/admin/tnsnames.ora</code></p>
<p>&nbsp;</p>
<h2>Install DBD::Oracle</h2>
<p>It's time to finally install DBD::Oracle. Go to your CPAN build directory and <code>cd</code> into <code>DBD-Oracle-*</code>. As a user having the environment variable set from the previous section, run Makefile.PL portion. </p>
<p><code>$ perl Makefile.PL</code></p>
<p>There's no need to set INC or LIB with the <code>alien</code> approach, but if you run into any issues, try giving Makefile.PL the path to your include dir for INC, and lib dir for LIB.</p>
<p>Next, run </p>
<p><code>$ make</code>. </p>
<p>It will raise a few warnings, but unless it exits with an error, you should be OK.</p>
<p>The next logical step is to run make test. However, this will undoubtedly fail unless you have a valid entry in your tnsnames.ora file. If you don't, you can skip this test and hope that everything works later on. Otherwise, update your <strong>tnsnames.ora</strong> file with a valid entry, and set one more environment variable before running the test:</p>
<p><code>$ export ORACLE_USERID="user/passwd@tns_entry_name"</code><br />
<code>$ make test</code></p>
<p>This is usually the hardest part to pass with total success. Many things can go wrong. In my case, the valid entry I use doesn't have full grants to the user I log in as. This always triggers an error on the create/access sequences portion of the testing. I simply ignore it nowadays - make sure you analyze your test results thoroughly before choosing to ignore the errors as well.</p>
<p>Now that the testing is over, simply run<br />
<code>$ make install</code><br />
as a super user and you're all set!</p>

<p><a href="http://feedads.g.doubleclick.net/~a/SCOmznHFoZ_WxwHUe0qXln-e9HQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/SCOmznHFoZ_WxwHUe0qXln-e9HQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/SCOmznHFoZ_WxwHUe0qXln-e9HQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/SCOmznHFoZ_WxwHUe0qXln-e9HQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=6PI9YmkLe7U:lSb86UNwABc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=6PI9YmkLe7U:lSb86UNwABc:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=6PI9YmkLe7U:lSb86UNwABc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=6PI9YmkLe7U:lSb86UNwABc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=6PI9YmkLe7U:lSb86UNwABc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=6PI9YmkLe7U:lSb86UNwABc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=6PI9YmkLe7U:lSb86UNwABc:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/6PI9YmkLe7U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/07/12/perl-installing-dbdoracle-on-ubuntu-904-and-oracle-instant-client/feed/</wfw:commentRss>
		<slash:comments>44</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/07/12/perl-installing-dbdoracle-on-ubuntu-904-and-oracle-instant-client/</feedburner:origLink></item>
		<item>
		<title>Didn’t find what you came for?</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/9Gs-P-aNOJc/</link>
		<comments>http://usestrict.net/2009/06/22/didnt-find-what-you-came-for/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 11:35:35 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=760</guid>
		<description>The cool thing about blogging software is that it shows the blogger all sorts of interesting information, such as the number of visitors, or the search string that led them to the blog. I see lots of interesting search strings, but I keep wondering if the users actually found what they were looking for. That [...]</description>
			<content:encoded><![CDATA[<p>The cool thing about blogging software is that it shows the blogger all sorts of interesting information, such as the number of visitors, or <strong>the search string that led them to the blog</strong>.</p>
<p>I see lots of interesting search strings, but I keep wondering if the users actually found what they were looking for. That said, please be kind and leave a message telling me if you found what you wanted, and if you didn't, please say what it was and I'll try to cover that in my posts.</p>
<p>You can leave your message either as a comment here, or <a href="/contact/">send me an email through the contact form</a>.</p>
<p>Thanks!!</p>

<p><a href="http://feedads.g.doubleclick.net/~a/3MMvYdenR2n1MnQWo_g8HZ18Is0/0/da"><img src="http://feedads.g.doubleclick.net/~a/3MMvYdenR2n1MnQWo_g8HZ18Is0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/3MMvYdenR2n1MnQWo_g8HZ18Is0/1/da"><img src="http://feedads.g.doubleclick.net/~a/3MMvYdenR2n1MnQWo_g8HZ18Is0/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=9Gs-P-aNOJc:8psEJRccV90:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=9Gs-P-aNOJc:8psEJRccV90:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=9Gs-P-aNOJc:8psEJRccV90:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=9Gs-P-aNOJc:8psEJRccV90:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=9Gs-P-aNOJc:8psEJRccV90:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=9Gs-P-aNOJc:8psEJRccV90:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=9Gs-P-aNOJc:8psEJRccV90:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/9Gs-P-aNOJc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/06/22/didnt-find-what-you-came-for/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/06/22/didnt-find-what-you-came-for/</feedburner:origLink></item>
		<item>
		<title>New Tech Jobs section</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/EeTM2kOFFIs/</link>
		<comments>http://usestrict.net/2009/06/13/new-perl-jobs-section/#comments</comments>
		<pubDate>Sat, 13 Jun 2009 07:00:33 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Jobs]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Perl Jobs]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=559</guid>
		<description>I've added a Tech Jobs page to the main pages section (right under the header) for those who are looking for jobs. Right now it only has the RSS from jobs.perl.org, but I intend to create a mash-up from several sites in the future. Update: Added craigslist.com search for Perl jobs in Canada (Vancouver only). [...]</description>
			<content:encoded><![CDATA[<p>I've added a <a href="/perl-jobs/" target="_blank">Tech Jobs</a> page to the main pages section (right under the header) for those who are looking for jobs. <del datetime="2009-06-08T12:27:50+00:00">Right now it only has the RSS from jobs.perl.org</del>, but I intend to create a mash-up from several sites <del datetime="2009-06-08T12:27:50+00:00">in the future</del>.</p>
<p><strong>Update:</strong> Added craigslist.com search for Perl jobs in Canada <del datetime="2009-06-09T13:53:18+00:00">(Vancouver only). Next is to add some fields which allow folks to select keywords and places</del> (Done! See update below).</p>
<p><strong>Update:</strong> The Feed fetcher now works with craigslist.com worldwide. You can also use search keys for feeds that accept them.</p>
<p><strong>Update (6/13/09):</strong> monster.com added with 192 countries (!!). Since some sources accept keywords and others don't, the form will now tell you so. Also, modified the form to allow blank keywords for some sources. The issue is that craigslist uses a totally separate query for blank keywords, and right now the fetcher doesn't handle alternate query strings per source. <strong>Total Sources: 4. Total feeds: 708.</strong></p>
<p>Good luck job-hunting!</p>
<p>Vinny.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/OqTKtz2DLyqkh8SVKJ6kLYT_QOg/0/da"><img src="http://feedads.g.doubleclick.net/~a/OqTKtz2DLyqkh8SVKJ6kLYT_QOg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/OqTKtz2DLyqkh8SVKJ6kLYT_QOg/1/da"><img src="http://feedads.g.doubleclick.net/~a/OqTKtz2DLyqkh8SVKJ6kLYT_QOg/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=EeTM2kOFFIs:a7NK9qAOrzk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=EeTM2kOFFIs:a7NK9qAOrzk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=EeTM2kOFFIs:a7NK9qAOrzk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=EeTM2kOFFIs:a7NK9qAOrzk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=EeTM2kOFFIs:a7NK9qAOrzk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=EeTM2kOFFIs:a7NK9qAOrzk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=EeTM2kOFFIs:a7NK9qAOrzk:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/EeTM2kOFFIs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/06/13/new-perl-jobs-section/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/06/13/new-perl-jobs-section/</feedburner:origLink></item>
		<item>
		<title>Upgrade to WordPress 2.8… IF YOU DARE!!</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/p5w3s68gk6M/</link>
		<comments>http://usestrict.net/2009/06/11/upgrade-to-wordpress-28-if-you-dare/#comments</comments>
		<pubDate>Thu, 11 Jun 2009 22:11:59 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=744</guid>
		<description>Seriously - **DON'T!** (did I stress that enough?) Not unless you've tested it well on a non-production machine. It's been known to break themes and plugins. My Advertising Manager plugin is still broken as of this writing, and there's no automatic downgrading. If you were hasty like me and ended up getting in trouble with [...]</description>
			<content:encoded><![CDATA[<p>Seriously - <strong><em>**DON'T!**</em></strong> (did I stress that enough?) Not unless you've tested it well on a non-production machine. It's been known to break themes and plugins. My Advertising Manager plugin is still broken as of this writing, and there's no automatic downgrading.</p>
<p>If you were hasty like me and ended up getting in trouble with the blasted 2.8 version, check this link on some steps to perform the downgrade.</p>
<p><a href="http://christastjean.co.uk/?p=2964">http://christastjean.co.uk/</a></p>

<p><a href="http://feedads.g.doubleclick.net/~a/jUUYyTUE54IrAtBbf6_mN-ceYYw/0/da"><img src="http://feedads.g.doubleclick.net/~a/jUUYyTUE54IrAtBbf6_mN-ceYYw/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/jUUYyTUE54IrAtBbf6_mN-ceYYw/1/da"><img src="http://feedads.g.doubleclick.net/~a/jUUYyTUE54IrAtBbf6_mN-ceYYw/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=p5w3s68gk6M:Z1JVmd3_6lc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=p5w3s68gk6M:Z1JVmd3_6lc:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=p5w3s68gk6M:Z1JVmd3_6lc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=p5w3s68gk6M:Z1JVmd3_6lc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=p5w3s68gk6M:Z1JVmd3_6lc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=p5w3s68gk6M:Z1JVmd3_6lc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=p5w3s68gk6M:Z1JVmd3_6lc:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/p5w3s68gk6M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/06/11/upgrade-to-wordpress-28-if-you-dare/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/06/11/upgrade-to-wordpress-28-if-you-dare/</feedburner:origLink></item>
		<item>
		<title>Recursion with Perl and CDS</title>
		<link>http://feedproxy.google.com/~r/UseStrict/~3/FGYInogA26c/</link>
		<comments>http://usestrict.net/2009/06/10/recursion-with-perl-and-cds/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 22:16:10 +0000</pubDate>
		<dc:creator>Vinny</dc:creator>
				<category><![CDATA[Perl]]></category>
		<category><![CDATA[CDS]]></category>
		<category><![CDATA[complex data structures]]></category>
		<category><![CDATA[recursion]]></category>
		<category><![CDATA[subroutine]]></category>
		<category><![CDATA[trim]]></category>
		<category><![CDATA[trimming]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=720</guid>
		<description>Recursion on Perl Complex Data Structures made easy.</description>
			<content:encoded><![CDATA[<p><strong>Update</strong>: Changed subroutine to comply with <a href="http://www.amazon.com/gp/product/0596001738?ie=UTF8&#038;tag=usst-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=0596001738" target="_blank">Perl Best Practices</a><img src="http://www.assoc-amazon.com/e/ir?t=usst-20&#038;l=as2&#038;o=1&#038;a=0596001738" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><strong>Update2</strong>: Removed the prototype from the subroutine.</p>
<p>I've always had a problem with recursion. Not with the general theory that a function will call itself, etc - no, that's easy. The hard part was when I had to deal with complex data structures in Perl (an array- or hashref containing a hash of arrays of hashes, a gazillion levels deep). Well, I guess anyone would have a hard time with that kind of data.</p>
<p>Anyway, in this post I don't intend to get all complicated explaining all the kinds of recursions out there. If you want that, check <a href="http://en.wikipedia.org/wiki/Recursion_(computer_science)" target="_blank">this article at wikipedia</a>. What I do want to do is help all of those who are in the situation I was in, by explaining in the simplest way possible how to deal with this scenario.<span id="more-720"></span></p>
<p>Let's start with a need. I have a complex data structure that needs its spaces trimmed on both sides. But since I'm lazy, I'd like my subroutine to modify the data directly, and not return the modified value (pass by reference, not pass by value). </p>
<p>Here's our data structure:</p>
<p>&nbsp;</p>
<pre class="brush:perl">
    my $data = [
                       {
                          key1 => '   trim me!   ',
                          key2 => '   trim me too!    ',
                       },
                       [
                          'some element to trim   ',
                          '    another one    ',
                       ],
                       '    a simple string needing trimming    ',
                  ];
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code>$data explained</code>:  an array containing 3 elements: element 0 is a hashref of keys <code>"key1"</code> and <code>"key2"</code>, element 1 is an arrayref of 2 elements. Element 3 is a simple string. All values have some extra spaces that need trimming (or so they say). We could use whatever number of levels and data types we want (except for anonymous subroutines, I guess - let's not get too complicated).</p>
<p>Now, to trim all that, I want to be able to simply call <code>trim()</code> à la PHP. </p>
<p>&nbsp;</p>
<pre class="brush:perl">
     trim($data); # note the lack of the lvalue (lvalue = rvalue)
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>I also want it to accept simple arrays and hashes, and the references thereof: <code>trim(@array); trim(\@array); trim(%hash); trim(\%hash); trim($string)</code>. After all, I never know what kind of data my colleagues will be working with. Better have it deal with everything.</p>
<p>The logic to do that is this:  our subroutine will have to do the trimming (s///g) on scalars only. For that, it has to check if the data it received is a hash, array, etc, and if it is, iterate through each element and trim the value... but only if the element is not itself a hash, array, etc. Found it confusing? No problem, it really is.</p>
<p>In Perl, if I tried to remove the white space from element 0 of my <code>$data</code>  variable, it wouldn't work. The reason being is that if I printed <code>$data->[0]</code> onto the screen, I'd get a funny looking output, something like <code>HASH(0x1004f5f0)</code>. That's Perl's way of saying that you have a HASH structure stored in memory position 0x1004f5f0. You can try to trim the spaces off of that string, but it won't do you any good. The elements of your hash will still be untouched. That's why you need to <em>de-reference</em> your data structures and dive into them.</p>
<p>To de-reference a structure is simple, just add a % in front of the variable if it's a hashref, or an @ if it's an array. But how do you know which is which? Use <code>ref()</code>.</p>
<p>&nbsp;</p>
<pre class="brush:perl">
       print ref($data->[0]) . "\n"; # HASH
       print ref($data->[1]) . "\n"; # ARRAY
       print ref($data->[3]) . "\n"; # empty string, which is false
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code>ref()</code> tells you what kind of data you are dealing with. It returns <code>CODE</code> if you have a closure or anonymous subroutine, but we're not going there today.</p>
<p>So, now that we know how to identify the type of element we're going to be working with, we can build our subroutine...</p>
<p>&nbsp;</p>
<pre class="brush:perl">
sub trim() {
	for my $param (@_) {
		if (ref($param) eq 'ARRAY') {
			for my $element (@{$param}) {
				trim($element);
			}
		}
		elsif (ref($param) eq 'HASH') {
			for my $val (values %{$param}) {
				trim($val);
			}
		}
		elsif (ref($param) eq 'CODE') {
			return;
		}
		else {
			$param =~ s/(^\s+|\s+$)//g;
		}
	}
}
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code>trim()</code> explained:</p>
<p>We're working with passing elements by reference instead of by value. This means that the elements themselves will be modified - no need to return any data. The first thing we do is to iterate through all parameters passed to <code>trim()</code>. In a subroutine, parameters (in our case, variables) are populated into the special <code>@_</code> array, allowing us to call <code>trim($var1, $var2, $var3)</code>  if we want.</p>
<p>We iterate through all elements of <code>@_</code> and verify if they are an Array. If they are, we iterate through each of their elements once, and call <code>trim()</code> again against them. That will handle as many nested arrays we want (or that your computer can handle). Now we have to make it deal with hashes. Same technique - use <code>ref()</code>  to see if it's a hash. If it is, then iterate through each of its key/pair elements. There are several ways to do that. I personally prefer calling <code>keys</code>  to get the keys and use them to fetch the values of the hash. The value of the hash is passed to <code>trim()</code> for more validation. We also check to see if we received a <code>sub { }</code> (anonymous subroutine). In that case, we do nothing, just return.</p>
<p>Finally, after handling Arrays, Hashes and Anonymous subroutines, we can set up the actual trimming of the strings. We take the <code>$_[$i]</code> which is the parameter passed and remove the leading and trailing spaces with one neat substitution: <code>^s\+</code> stands for leading spaces, <code>\s+$</code> stands for trailing spaces, and it's all joined by the <code>(  |  )</code> (this or that). We only call it once because we're using the global (g) modifier of the substitution <code>s///g</code>.</p>
<p>And that's all there is to it!</p>
<p><em>A note on prototypes:</em> This post generated a healthy discussion on prototypes. I had originally added the dollar prototype to the <code>trim()</code> subroutine, but that was forcing it to accept only scalars (strings and references), and not working with normal hashes and arrays. Thanks to everyone who participated in the discussion.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>

<p><a href="http://feedads.g.doubleclick.net/~a/K6ZRfsGsF8MGWZTBLRatfVYK2D0/0/da"><img src="http://feedads.g.doubleclick.net/~a/K6ZRfsGsF8MGWZTBLRatfVYK2D0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/K6ZRfsGsF8MGWZTBLRatfVYK2D0/1/da"><img src="http://feedads.g.doubleclick.net/~a/K6ZRfsGsF8MGWZTBLRatfVYK2D0/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/UseStrict?a=FGYInogA26c:-oo5A5J91WM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=FGYInogA26c:-oo5A5J91WM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=FGYInogA26c:-oo5A5J91WM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=FGYInogA26c:-oo5A5J91WM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=FGYInogA26c:-oo5A5J91WM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/UseStrict?i=FGYInogA26c:-oo5A5J91WM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/UseStrict?a=FGYInogA26c:-oo5A5J91WM:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/UseStrict?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/UseStrict/~4/FGYInogA26c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/06/10/recursion-with-perl-and-cds/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		<feedburner:origLink>http://usestrict.net/2009/06/10/recursion-with-perl-and-cds/</feedburner:origLink></item>
	</channel>
</rss>
