<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.2.3" -->
<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/"
	>

<channel>
	<title>eXfer network</title>
	<link>http://www.exfer.net/blog</link>
	<description>a blog from david_kw</description>
	<pubDate>Fri, 29 Feb 2008 16:36:33 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2.3</generator>
	<language>en</language>
			<item>
		<title>In A Row Activity in Development for the XO (fancy Tic Tac Toe)</title>
		<link>http://www.exfer.net/blog/2008/02/29/in-a-row-activity-in-development-for-the-xo-fancy-tic-tac-toe/</link>
		<comments>http://www.exfer.net/blog/2008/02/29/in-a-row-activity-in-development-for-the-xo-fancy-tic-tac-toe/#comments</comments>
		<pubDate>Fri, 29 Feb 2008 08:12:22 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[OLPC]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2008/02/29/in-a-row-activity-in-development-for-the-xo-fancy-tic-tac-toe/</guid>
		<description><![CDATA[Earlier this month I decided to write my first activity for the OLPC XO laptop since I believe the best way to learn is by doing.  Since I have a background in computer games I choose to make a simple game.  I decided to write the ever-popular-with-kids game Tic Tac Toe.  My [...]]]></description>
			<content:encoded><![CDATA[<p>Earlier this month I decided to write my first <a href="http://wiki.laptop.org/go/Activity" target="_blank">activity</a> for the <a href="http://www.laptop.org" target="_blank">OLPC XO laptop</a> since I believe the best way to learn is by doing.  Since I have a background in computer games I choose to make a simple game.  I decided to write the ever-popular-with-kids game <a href="http://en.wikipedia.org/wiki/Tic_tac_toe" target="_blank">Tic Tac Toe</a>.  My primary thought was that if the computer could play Tic Tac Toe then I wouldn&#8217;t have to.</p>
<p>As it turns out, writing a Tic Tac Toe game is about as boring as playing one but since I&#8217;d already written code to create a grid, draw Xs and Os, and come up with a plan for a grid based computer AI, I decided that instead of dropping the activity all together I&#8217;d alter it to allow larger grids and more tokens in a row to win.  This would allow playing games like <a href="http://en.wikipedia.org/wiki/Gomoku" target="_blank">Go-moku</a> which I remember playing against the computer when I was in high school.  That was the birth of the <a href="http://www.exfer.net/olpc/inarow-1.xo" target="_blank">In A Row Activity</a>.  </p>
<p>The activity is based on the <a href="http://wiki.laptop.org/go/OLPCGames" target="_blank">OLPCGames</a> wrapper for <a href="http://www.pygame.org/" target="_blank">pygame</a> which is already installed on the XO.  I highly recommend using it if you plan to write a game activity.</p>
<p>In any case, <a href="http://www.exfer.net/olpc/inarow-1.xo" target="_blank">click here to download the In A Row Activity</a> and try it for yourself.  You can take a look at <a href="http://www.exfer.net/olpc/inarow-screenshot.png" target="_blank">a screenshot here</a>.  Let me know what you think or if you find any problems.</p>
<p><a href="http://www.exfer.net/olpc/inarow-screenshot.png" target="_blank"><img src="http://www.exfer.net/olpc/inarow-screenshot.png" alt="In A Row Activity screenshot" style="width:400px;height:300px;margin:0 auto;display:block;"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2008/02/29/in-a-row-activity-in-development-for-the-xo-fancy-tic-tac-toe/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A cross browser changeCSS function to alter, add, or delete CSS rules</title>
		<link>http://www.exfer.net/blog/2008/01/26/a-cross-browser-changecss-function-to-alter-add-or-delete-css-rules/</link>
		<comments>http://www.exfer.net/blog/2008/01/26/a-cross-browser-changecss-function-to-alter-add-or-delete-css-rules/#comments</comments>
		<pubDate>Sat, 26 Jan 2008 17:00:10 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2008/01/26/a-cross-browser-changecss-function-to-alter-add-or-delete-css-rules/</guid>
		<description><![CDATA[Last year I needed a function to change CSS rules for one of my projects, so I put together a function called changeCSS() which allowed me to change, add or delete a CSS rule.  I looked at various resources and the work was heavily influenced by code from David Flanagan and Shawn Olson.  [...]]]></description>
			<content:encoded><![CDATA[<p>Last year I needed a function to change CSS rules for one of my projects, so I put together a function called changeCSS() which allowed me to change, add or delete a CSS rule.  I looked at various resources and the work was heavily influenced by code from <a href="http://www.davidflanagan.com/" target="_blank">David Flanagan</a> and <a href="http://www.shawnolson.net/" target="_blank">Shawn Olson</a>.  It worked great for all the cases I needed it in my project.  My plan was to rigorously test it to make sure it worked in other cases I hadn&#8217;t used then post it here, but over time it has become clear that isn&#8217;t going to happen.  So I decided I&#8217;d just put it out here as &#8220;yet another semi-tested but handy function&#8221; that people can look at for reference.</p>
<p>Anywhere, here is the function.</p>
<div class="quickcodenoclick"><code><br />
var exfer = window.exfer || {};<br />
exfer.changeCSS = function (selector, stylename, value) {<br />
&nbsp;&nbsp;var ss, rules;<br />
&nbsp;<br />
&nbsp;&nbsp;// make sure there is a stylesheet available<br />
&nbsp;&nbsp;if (document.styleSheets.length &lt;= 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (document.createStyleSheet) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.createStyleSheet();<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var styleTag = document.createElement(&quot;style&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;styleTag.type = &quot;text/css&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.getElementsByTagName(&quot;head&quot;)[0].appendChild(styleTag);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;// convert the stylename to camel case if necessary<br />
&nbsp;&nbsp;ccstylename = (stylename || &quot;&quot;).replace(/\-(\w)/g, function (m, c) { return (c.toUpperCase()); });<br />
&nbsp;&nbsp;ccstylename = (ccstylename == &#039;float&#039;) ? &#039;cssFloat&#039; : ccstylename;<br />
&nbsp;&nbsp;selector = selector.toLowerCase();<br />
&nbsp;<br />
&nbsp;&nbsp;// loop to delete or change the css<br />
&nbsp;&nbsp;for (var i = 0; i &lt; document.styleSheets.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;ss = document.styleSheets[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules = ss.cssRules || ss.rules;<br />
&nbsp;&nbsp;&nbsp;&nbsp;catch (e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules = []<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;for (var j = 0, len = rules.length; j &lt; len; j++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (rules[j].selectorText &amp;&amp; rules[j].selectorText.toLowerCase() == selector) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (value != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules[j].style[ccstylename] = value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (ss.deleteRule) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ss.deleteRule(j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else if (ss.removeRule) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ss.removeRule(j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// poor man&#039;s delete<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules[j].style.cssText = &quot;&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;if (stylename &amp;&amp; value) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;// if the selector wasn&#039;t found and isn&#039;t supposed to be deleted then add it<br />
&nbsp;&nbsp;&nbsp;&nbsp;ss = document.styleSheets[0];<br />
&nbsp;&nbsp;&nbsp;&nbsp;rules = ss.cssRules || ss.rules;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (ss.insertRule) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ss.insertRule(selector + &quot;{&quot; + stylename + &quot;:&quot; + value + &quot;; }&quot;, rules.length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else if (ss.addRule) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ss.addRule(selector, stylename + &quot;:&quot; + value + &quot;;&quot;, rules.length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new Error(&quot;Selector not found and add/insert rule not supported.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
};<br />
</code><br/></div>
<p><script type="text/javascript">
var exfer = window.exfer || {};
exfer.changeCSS = function (selector, stylename, value) {
  var ss, rules;
  // make sure there is a stylesheet available
  if (document.styleSheets.length <= 0) {
    if (document.createStyleSheet) {
      document.createStyleSheet();
    } else {
      var styleTag = document.createElement("style");
      styleTag.type = "text/css";
      document.getElementsByTagName("head")[0].appendChild(styleTag);
    }
  }
  // convert the stylename to camel case if necessary
  ccstylename = (stylename || "").replace(/\-(\w)/g, function (m, c) { return (c.toUpperCase()); });
  ccstylename = (ccstylename == "float") ? "cssFloat" : ccstylename;
  selector = selector.toLowerCase();
  // loop to delete or change the css
  for (var i = 0; i < document.styleSheets.length; i++) {
    ss = document.styleSheets[i];
    try {
      rules = ss.cssRules || ss.rules;
    } catch (e) { 
      rules = []; 
    }
    for (var j = 0, len = rules.length; j < len; j++) {
      if (rules[j].selectorText) if (rules[j].selectorText.toLowerCase() == selector) { // problems in wordpress with 2 ampersands for and
        if (value != null) {
          rules[j].style[ccstylename] = value;
        } else {
          if (ss.deleteRule) {
            ss.deleteRule(j);
          } else if (ss.removeRule) {
            ss.removeRule(j);
          } else {
            // poor man\'s delete
            rules[j].style.cssText = "";
          }
        }
        return;
      }
    }
  }
  if (stylename) if (value) { // wordpress problems with 2 ampersands
    // if the selector wasn\'t found and isn\'t supposed to be deleted then add it
    ss = document.styleSheets[0];
    rules = ss.cssRules || ss.rules;
    if (ss.insertRule) {
      ss.insertRule(selector + "{" + stylename + ":" + value + "; }", rules.length);
    } else if (ss.addRule) {
      ss.addRule(selector, stylename + ":" + value + ";", rules.length);
    } else {
      throw new Error("Selector not found and add/insert rule not supported.");
    }
  }
};
</script></p>
<p>Below is a test div that starts bold and you can change the color.  You can even delete the whole rule and remake it.</p>
<style type="text/css">
  #changediv { font-weight: bolder; }
</style>
<div id="changediv">A test DIV</div>
<p><button onclick='exfer.changeCSS("#changediv", "background-color", "yellow");'>Turn yellow</button> exfer.changeCSS(&#8221;#changediv&#8221;, &#8220;background-color&#8221;, &#8220;yellow&#8221;);</p>
<p><button onclick='exfer.changeCSS("#changediv", "background-color", "green");'>Turn green</button> exfer.changeCSS(&#8221;#changediv&#8221;, &#8220;background-color&#8221;, &#8220;green&#8221;);</p>
<p><button onclick='exfer.changeCSS("#changediv", "background-color", "");'>Delete background</button> exfer.changeCSS(&#8221;#changediv&#8221;, &#8220;background-color&#8221;, &#8220;&#8221;);</p>
<p><button onclick='exfer.changeCSS("#changediv", "background-color");'>Delete whole rule</button> exfer.changeCSS(&#8221;#changediv&#8221;, &#8220;background-color&#8221;);</p>
<p>Overall I think it is a handy function.  I did my minimal testing in IE6/7, FF2, Opera 9, and Safari 3 all in Windows.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2008/01/26/a-cross-browser-changecss-function-to-alter-add-or-delete-css-rules/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Happy Holidays</title>
		<link>http://www.exfer.net/blog/2007/12/21/happy-holidays/</link>
		<comments>http://www.exfer.net/blog/2007/12/21/happy-holidays/#comments</comments>
		<pubDate>Fri, 21 Dec 2007 17:20:17 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[OLPC]]></category>

		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/12/21/happy-holidays/</guid>
		<description><![CDATA[Well I&#8217;m off for a vacation for the next few weeks.  I have my OLPC and some time so I&#8217;m looking forward to messing around with it.  Although it is difficult to touch type, so far I love this little thing.  It feels so very compact and durable.  Unlike my Dell, [...]]]></description>
			<content:encoded><![CDATA[<p>Well I&#8217;m off for a vacation for the next few weeks.  I have my OLPC and some time so I&#8217;m looking forward to messing around with it.  Although it is difficult to touch type, so far I love this little thing.  It feels so very compact and durable.  Unlike my Dell, I actually unplug this laptop and take it to different areas of my house.  </p>
<p>Anyway, here is a picture of my new laptop in living color. :)</p>
<p><a href='http://www.exfer.net/blog/wp-content/uploads/2008/01/xo.jpg' title='My XO'><img src='http://www.exfer.net/blog/wp-content/uploads/2008/01/xo.thumbnail.jpg' alt='My XO' /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/12/21/happy-holidays/feed/</wfw:commentRss>
		</item>
		<item>
		<title>I Purchased Two OLPC XOs Today</title>
		<link>http://www.exfer.net/blog/2007/11/12/i-purchased-two-olpc-xos-today/</link>
		<comments>http://www.exfer.net/blog/2007/11/12/i-purchased-two-olpc-xos-today/#comments</comments>
		<pubDate>Mon, 12 Nov 2007 18:34:08 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[OLPC]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/11/12/i-purchased-two-olpc-xos-today/</guid>
		<description><![CDATA[Well I went ahead and bought two OLPC XO laptop computers today using the OLPC Give One, Get One program.  I&#8217;ve been following the program since it was first announce when it seemed like a pipe dream.  Yes, the price has almost doubled from the goal of $100 but it&#8217;s amazing what a [...]]]></description>
			<content:encoded><![CDATA[<p>Well I went ahead and bought two <a href="http://www.laptop.org/" target="_blank">OLPC XO laptop computers</a> today using the <a href="http://www.laptopgiving.org/en/index.php" target="_blank">OLPC Give One, Get One</a> program.  I&#8217;ve been following the program since it was first announce when it seemed like a pipe dream.  Yes, the price has almost doubled from the goal of $100 but it&#8217;s amazing what a powerful idea can do.  The whole computer industry has been shaken by these little laptops with both Microsoft and Intel, who initially slammed the idea, trying to figure out how to get on board before their global market share starts eroding in big chunks.</p>
<p>Now I&#8217;ll wait impatiently for them to arrive.  I can&#8217;t wait because I have access to a few older DOS programs that I&#8217;m planning to try to port to the XO.  It&#8217;s going to be fun. :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/11/12/i-purchased-two-olpc-xos-today/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Another Curry Function for more Closure Options</title>
		<link>http://www.exfer.net/blog/2007/10/28/another-curry-function-for-more-closure-options/</link>
		<comments>http://www.exfer.net/blog/2007/10/28/another-curry-function-for-more-closure-options/#comments</comments>
		<pubDate>Sun, 28 Oct 2007 23:21:48 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/10/28/another-curry-function-for-more-closure-options/</guid>
		<description><![CDATA[There are a lot of curry functions examples out there so I decided I&#8217;d share mine as well.  The code was inspired by a blog posting from Dustin Diaz  who was in turn inspired by one from Dan Webb.   Those posts can probably do an overall better job of explaining currying [...]]]></description>
			<content:encoded><![CDATA[<p>There are a lot of curry functions examples out there so I decided I&#8217;d share mine as well.  The code was inspired by a <a href="http://www.dustindiaz.com/javascript-curry/" target="_blank">blog posting from Dustin Diaz</a>  who was in turn inspired by <a href="http://www.danwebb.net/2006/11/3/from-the-archives-cleaner-callbacks-with-partial-application" target="_blank">one from Dan Webb</a>.   Those posts can probably do an overall better job of explaining currying than I can so I&#8217;m not going to go in to the idea of currying in any great detail.  So I&#8217;ll just say the currying pattern is useful for attaching data to a function in a way that avoids using global variables and simplifies the use of closure.</p>
<p>When people first start programming in JavaScript they often use global variables to save data for later function calls like this:</p>
<p><a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode211');">Global Demo</a></p>
<div id="quickcode211" class="quickcode"><code><br />
&lt;script type=&quot;text/javascript&quot;&gt;<br />
&nbsp;&nbsp;var global_target;<br />
&nbsp;&nbsp;var global_oldText;<br />
&nbsp;<br />
&nbsp;&nbsp;function doItGlobal(e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;e = e || window.event;<br />
&nbsp;&nbsp;&nbsp;&nbsp;global_target = e.target || e.srcElement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;global_oldText = global_target.innerHTML;<br />
&nbsp;&nbsp;&nbsp;&nbsp;global_target.innerHTML = &quot;Click!&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function () {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;global_target.innerHTML = global_oldText;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, 1000); <br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return (false);<br />
&nbsp;&nbsp;}<br />
&lt;/script&gt;<br />
&nbsp;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItGlobal(event);&quot;&gt;Global test&lt;/a&gt;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItGlobal(event);&quot;&gt;Test 2&lt;/a&gt;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItGlobal(event);&quot;&gt;Test 3&lt;/a&gt;<br />
</code><br/></div>
<p><script type="text/javascript">
  var global_target;
  var global_oldText;
  function doItGlobal(e) {
    e = e || window.event;
    global_target = e.target || e.srcElement;
    global_oldText = global_target.innerHTML;
    global_target.innerHTML = "Click!";
    setTimeout(function () {
          global_target.innerHTML = global_oldText;
        }, 1000); 
    return (false);
  }
</script></p>
<p><a href="#" onclick="return doItGlobal(event);">Global test</a> <a href="#" onclick="return doItGlobal(event);">Test 2</a> <a href="#" onclick="return doItGlobal(event);">Test 3</a></p>
<p>Here you see a couple global variables are used to save the link that was clicked and the old text that was inside.  When clicking just one link at a time it works, but if you click more than one (in the one second time frame) the next click corrupts the global variables and the first link won&#8217;t reset to its old text correctly.  </p>
<p>One way to solve this problem is using closure instead of global variables like this:</p>
<p><a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode212');">Closure Demo</a></p>
<div id="quickcode212" class="quickcode"><code><br />
&lt;script type=&quot;text/javascript&quot;&gt;<br />
&nbsp;&nbsp;function doItClosure(e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;e = e || window.event;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var target = e.target || e.srcElement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var oldText = target.innerHTML;<br />
&nbsp;&nbsp;&nbsp;&nbsp;target.innerHTML = &quot;Click!&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function () {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;target.innerHTML = oldText;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, 1000); <br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return (false);<br />
&nbsp;&nbsp;}<br />
&lt;/script&gt;<br />
&nbsp;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItClosure(event);&quot;&gt;Closure test&lt;/a&gt;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItClosure(event);&quot;&gt;Closure test 2&lt;/a&gt;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItClosure(event);&quot;&gt;Closure test 3&lt;/a&gt;<br />
</code><br/></div>
<p><script type="text/javascript">
  function doItClosure(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    var oldText = target.innerHTML;
    target.innerHTML = "Click!";
    setTimeout(function () {
          target.innerHTML = oldText;
        }, 1000); 
    return (false);
  }
</script></p>
<p><a href="#" onclick="return doItClosure(event);">Closure test</a> <a href="#" onclick="return doItClosure(event);">Closure test 2</a> <a href="#" onclick="return doItClosure(event);">Closure test 3</a></p>
<p>This saves a unique copy of the data for each call and solves the previous problem.  Often this is a very clear and concise way to handle the problem.  But other times, usually when functions start getting more complex with multiple callbacks for multiple events, it can be hard to follow the trail of closure to see exactly which variables are attached to which internal functions.  That is when I find the curry pattern like this very useful:</p>
<p><a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode213');">Curry Demo</a></p>
<div id="quickcode213" class="quickcode"><code><br />
&lt;script type=&quot;text/javascript&quot;&gt;<br />
&nbsp;&nbsp;function doItCurry(e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;e = e || window.event;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var target = e.target || e.srcElement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;var oldText = target.innerHTML;<br />
&nbsp;&nbsp;&nbsp;&nbsp;target.innerHTML = &quot;Click!&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(exfer.curry(target, function (text) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.innerHTML = text;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, oldText), 1000); <br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return (false);<br />
&nbsp;&nbsp;}<br />
&lt;/script&gt;<br />
&nbsp;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItCurry(event);&quot;&gt;Curry test&lt;/a&gt;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItCurry(event);&quot;&gt;Curry test 2&lt;/a&gt;<br />
&lt;a href=&quot;#&quot; onclick=&quot;return doItCurry(event);&quot;&gt;Curry test 3&lt;/a&gt;<br />
</code><br/></div>
<p><script type="text/javascript">
var exfer = window.exfer || {};
exfer.curry = function (scope, func) {
  var s, f, n;
  // commented out because wordpress wants to replace the ampersands
  // if (typeof scope == \'function\' &#038;&#038; typeof func != \'function\') {
    // s = null; f = scope; n = 1;
  // } else {
    s = scope; f = func; n = 2;
  // }
  var args = Array.prototype.slice.call(arguments, n);
  return (function () {
        var o = s || this;
        var allArgs = args.concat(Array.prototype.slice.call(arguments, 0));
        return (f.apply(o, allArgs));
      });
};
  function doItCurry(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    var oldText = target.innerHTML;
    target.innerHTML = "Click!";
    setTimeout(exfer.curry(target, function (text) {
          this.innerHTML = text;
        }, oldText), 1000); 
    return (false);
  }
</script></p>
<p><a href="#" onclick="return doItCurry(event);">Curry test</a> <a href="#" onclick="return doItCurry(event);">Curry test 2</a> <a href="#" onclick="return doItCurry(event);">Curry test 3</a></p>
<p>Once you get used to the pattern you can see clearly that target and oldText are passed in to time timeout function callback where they are operated upon.  Internally the curry function also uses closure but it is hidden from the event handler.  Also a curry function can be used to assign scope to the &#8220;this&#8221; identifier in a function.  </p>
<p>In any case, here is my curry function:</p>
<div class="quickcodenoclick"><code><br />
var exfer = window.exfer || {};<br />
exfer.curry = function (scope, func) {<br />
&nbsp;&nbsp;var s, f, n;<br />
&nbsp;&nbsp;// make the scope parameter optional such that it keeps the original this value<br />
&nbsp;&nbsp;if (typeof scope == &#039;function&#039; &amp;&amp; typeof func != &#039;function&#039;) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;s = null; f = scope; n = 1;<br />
&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;s = scope; f = func; n = 2;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;// save the arguments to pass to the new function<br />
&nbsp;&nbsp;var args = Array.prototype.slice.call(arguments, n);<br />
&nbsp;&nbsp;return (function () {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// override the this scope if desired<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var o = s || this;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// add the arguments passed in to the other arguments<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var allArgs = args.concat(Array.prototype.slice.call(arguments, 0));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// call the function with the new scope and arguments<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (f.apply(o, allArgs));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
};<br />
</code><br/></div>
<p>It differs from Dustin&#8217;s in two ways.  First of all it can return a value which can be useful for some callbacks even if it isn&#8217;t so useful in the example I have above.  Second, it can accept arguments from the calling function.  Perhaps another example is in order.</p>
<p><a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode215');">Another Curry Demo</a></p>
<div id="quickcode215" class="quickcode"><code><br />
&lt;a id=&quot;demo1&quot; href=&quot;#&quot;&gt;Curry demo&lt;/a&gt;<br />
&lt;a id=&quot;demo2&quot; href=&quot;#&quot;&gt;Curry demo 2&lt;/a&gt;<br />
&lt;a id=&quot;demo3&quot; href=&quot;#&quot;&gt;Curry demo 3&lt;/a&gt;<br />
&lt;script type=&quot;text/javascript&quot;&gt;<br />
&nbsp;&nbsp;var arr = [ document.getElementById(&quot;demo1&quot;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.getElementById(&quot;demo2&quot;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.getElementById(&quot;demo3&quot;) ];<br />
&nbsp;&nbsp;for (i in arr) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;arr[i].onclick = exfer.curry(arr[i], function (e) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e = e || window.event;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.innerHTML = this.innerHTML + &quot;!&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (e.preventDefault) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.preventDefault();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.returnValue = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<br />
&nbsp;&nbsp;}<br />
&lt;/script&gt;<br />
</code><br/></div>
<p><a id="demo1" href="#">Curry demo</a> <a id="demo2" href="#">Curry demo 2</a> <a id="demo3" href="#">Curry demo 3</a><br />
<script type="text/javascript">
  var arr = [ document.getElementById("demo1"),
              document.getElementById("demo2"),
              document.getElementById("demo3") ];
  for (i in arr) {
    arr[i].onclick = exfer.curry(arr[i], function (e) { 
                                           e = e || window.event;
                                           this.innerHTML = this.innerHTML + "!";
                                           if (e.preventDefault) {
                                             e.preventDefault();
                                           } else {
                                             e.returnValue = false;
                                           }
                                           return (false);
                                         });
  }
</script></p>
<p>Here you can see an argument is passed to the curry function and it also returns a value.  These are the two additional features added to Dustin&#8217;s curry function.  They are pretty simple additions but very useful.  I recommend playing around with a curry function if you use a lot of callbacks to see how you like it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/10/28/another-curry-function-for-more-closure-options/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Yet another jQuery convert</title>
		<link>http://www.exfer.net/blog/2007/09/05/yet-another-jquery-convert/</link>
		<comments>http://www.exfer.net/blog/2007/09/05/yet-another-jquery-convert/#comments</comments>
		<pubDate>Thu, 06 Sep 2007 04:45:30 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/09/05/yet-another-jquery-convert/</guid>
		<description><![CDATA[As I&#8217;ve mentioned in previous posts, I have been going through a process of reviewing various JavaScript libraries and frameworks.  So yesterday I started looking at jQuery.  And I have to admit what I saw was impressive.  Not that it does anything that other libraries can&#8217;t do.  But rather that the [...]]]></description>
			<content:encoded><![CDATA[<p>As I&#8217;ve mentioned in previous posts, I have been going through a process of reviewing various JavaScript libraries and frameworks.  So yesterday I started looking at <a href="http://jquery.com">jQuery</a>.  And I have to admit what I saw was impressive.  Not that it does anything that other libraries can&#8217;t do.  But rather that the design of the library is wonderfully simple while still being powerful.  Within about an hour of reviewing the core jQuery library I felt comfortable with it.</p>
<p>So today I decided to toss out my own home rolled library and go with jQuery.  Although the custom library I wrote was working fine, I decided the cross browser issues that are bound to come up in testing would be easier to deal with if I used jQuery.  So the Chatkik internal chat application has been complete refactored with jQuery.  The chat container still uses <a href="http://developer.yahoo.com/yui">YUI</a> (which I also like but just isn&#8217;t quite as elegant as jQuery for simple tasks).</p>
<p>That being said, if you find something failing to work that used to work in Chatkik, this change is likely the reason.  Just let me know and I&#8217;ll take care of it ASAP.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/09/05/yet-another-jquery-convert/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Chat with Chatkik</title>
		<link>http://www.exfer.net/blog/2007/08/30/chat-with-chatkik/</link>
		<comments>http://www.exfer.net/blog/2007/08/30/chat-with-chatkik/#comments</comments>
		<pubDate>Thu, 30 Aug 2007 08:38:59 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/08/30/chat-with-chatkik/</guid>
		<description><![CDATA[I&#8217;ve been working recently with chatkik.com to develop an Ajax chat system.  Although there is still a lot of work to do, I received permission to put the current dev version up on my blog for some pre-alpha testing.  I know chat isn&#8217;t much fun without more than one person in the channel, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working recently with chatkik.com to develop an Ajax chat system.  Although there is still a lot of work to do, I received permission to put the current dev version up on my blog for some pre-alpha testing.  I know chat isn&#8217;t much fun without more than one person in the channel, but please feel free to check it out and comment if you have any thoughts about design or bugs or questions or anything else.  Just click on the red chatkik tab in the upper right if you want to see the current version.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/08/30/chat-with-chatkik/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Python grep Script with Multiple Files</title>
		<link>http://www.exfer.net/blog/2007/07/29/python-grep-script-with-multiple-files/</link>
		<comments>http://www.exfer.net/blog/2007/07/29/python-grep-script-with-multiple-files/#comments</comments>
		<pubDate>Sun, 29 Jul 2007 17:54:26 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[Non-Web Programming]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/08/03/python-grep-script-with-multiple-files/</guid>
		<description><![CDATA[The other day I was looking for a command-line grep I could use in Windows.  There were several options so I picked a python script that I found on Wikipedia (I chose a script since I have a health paranoia about spyware and such).  
Overall, the script had enough functionality for my purposes [...]]]></description>
			<content:encoded><![CDATA[<p>The other day I was looking for a command-line grep I could use in Windows.  There were several options so I picked <a href="http://www.vdesmedt.com/~vds2212/grep.html" target="_blank">a python script</a> that I found on <a href="http://en.wikipedia.org/wiki/Grep" target="_blank">Wikipedia</a> (I chose a script since I have a health paranoia about spyware and such).  </p>
<p>Overall, the script had enough functionality for my purposes with one exception.  It didn&#8217;t accept wildcards for multiple files.  It was only a few lines of code so I went ahead and added glob functionality and it seems to work fine.  In case it is useful to anyone else, here is the altered script.  Thanks <a href="http://www.vdesmedt.com/~vds2212/index.html" target="_blank">Vivian De Smedt</a> for the original.</p>
<p><a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode181');">grep.py</a></p>
<div id="quickcode181" class="quickcode"><code><br />
&quot;&quot;&quot;<br />
Usage: grep [OPTION]&#46;.. PATTERN [FILE] &#46;..<br />
Search for PATTERN in each FILE or standard input.<br />
Example: grep -i &#039;hello world&#039; menu.h main.c<br />
&nbsp;<br />
Regexp selection and interpretation:<br />
&nbsp;&nbsp;-E, &#45;-extended-regexp&nbsp;&nbsp;&nbsp;&nbsp; PATTERN is an extended regular expression<br />
&nbsp;&nbsp;-F, &#45;-fixed-strings&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PATTERN is a set of newline-separated strings<br />
&nbsp;&nbsp;-G, &#45;-basic-regexp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PATTERN is a basic regular expression<br />
&nbsp;&nbsp;-e, &#45;-regexp=PATTERN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;use PATTERN as a regular expression<br />
&nbsp;&nbsp;-f, &#45;-file=FILE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obtain PATTERN from FILE<br />
&nbsp;&nbsp;-w, &#45;-word-regexp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; force PATTERN to match only whole words<br />
&nbsp;&nbsp;-x, &#45;-line-regexp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; force PATTERN to match only whole lines<br />
&nbsp;&nbsp;-z, &#45;-null-data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a data line ends in 0 byte, not newline<br />
&nbsp;<br />
Miscellaneous:<br />
&nbsp;&nbsp;-s, &#45;-no-messages&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; suppress error messages<br />
&nbsp;&nbsp;-v, &#45;-invert-match&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select non-matching lines<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#45;-mmap&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;use memory-mapped input if possible<br />
&nbsp;<br />
Output control:<br />
&nbsp;&nbsp;-b, &#45;-byte-offset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print the byte offset with output lines<br />
&nbsp;&nbsp;-H, &#45;-with-filename&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print the filename for each match<br />
&nbsp;&nbsp;-h, &#45;-no-filename&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; suppress the prefixing filename on output<br />
&nbsp;&nbsp;-q, &#45;-quiet, &#45;-silent&nbsp;&nbsp;&nbsp;&nbsp; suppress all normal output<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#45;-binary-files=TYPE&nbsp;&nbsp; assume that binary files are TYPE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TYPE is &#039;binary&#039;, &#039;text&#039;, or &#039;without-match&#039;.<br />
&nbsp;&nbsp;-a, &#45;-text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equivalent to &#45;-binary-files=text<br />
&nbsp;&nbsp;-I&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equivalent to &#45;-binary-files=without-match<br />
&nbsp;&nbsp;-d, &#45;-directories=ACTION&nbsp;&nbsp;how to handle directories<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ACTION is &#039;read&#039;, &#039;recurse&#039;, or &#039;skip&#039;.<br />
&nbsp;&nbsp;-r, &#45;-recursive&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; equivalent to &#45;-directories=recurse.<br />
&nbsp;&nbsp;-L, &#45;-files-without-match only print FILE names containing no match<br />
&nbsp;&nbsp;-l, &#45;-files-with-matches&nbsp;&nbsp;only print FILE names containing matches<br />
&nbsp;&nbsp;-c, &#45;-count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; only print a count of matching lines per FILE<br />
&nbsp;&nbsp;-Z, &#45;-null&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print 0 byte after FILE name<br />
&nbsp;<br />
Context control:<br />
&nbsp;&nbsp;-NUM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;same as &#45;-context=NUM<br />
&nbsp;&nbsp;-U, &#45;-binary&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do not strip CR characters at EOL (MSDOS)<br />
&nbsp;&nbsp;-u, &#45;-unix-byte-offsets&nbsp;&nbsp; report offsets as if CRs were not there (MSDOS)<br />
&nbsp;<br />
`egrep&#039; means `grep -E&#039;.&nbsp;&nbsp;`fgrep&#039; means `grep -F&#039;.<br />
With no FILE, or when FILE is -, read standard input.&nbsp;&nbsp;If less than<br />
two FILEs given, assume -h.&nbsp;&nbsp;Exit status is 0 if match, 1 if no match,<br />
and 2 if trouble.<br />
&nbsp;<br />
Report bugs to &lt;bug-gnu-utils@gnu.org&gt;.&quot;&quot;&quot;<br />
&nbsp;<br />
import sys, re, getopt, glob<br />
&nbsp;<br />
class Queue:<br />
&nbsp;&nbsp;def __init__(self, size):<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.size = size<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.values = []<br />
&nbsp;<br />
&nbsp;&nbsp;def append(self, value):<br />
&nbsp;&nbsp;&nbsp;&nbsp;if self.size:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.values.append(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while len(self.values) &gt; self.size:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.values.pop(0)<br />
&nbsp;<br />
&nbsp;&nbsp;def pop(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;if self.values:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.values.pop(0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;return None<br />
&nbsp;<br />
&nbsp;&nbsp;def __len__(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;return len(self.values)<br />
&nbsp;<br />
&nbsp;&nbsp;def __getitem__(self, n):<br />
&nbsp;&nbsp;&nbsp;&nbsp;return self.values[n]<br />
&nbsp;<br />
def grep(pattern, f, options):<br />
&nbsp;&nbsp;if options.ignore_case:<br />
&nbsp;&nbsp;&nbsp;&nbsp;p = re.compile(pattern, re.I)<br />
&nbsp;&nbsp;else:<br />
&nbsp;&nbsp;&nbsp;&nbsp;p = re.compile(pattern)<br />
&nbsp;<br />
&nbsp;&nbsp;queue = Queue(options.before_context)<br />
&nbsp;&nbsp;line_nb = 0<br />
&nbsp;&nbsp;from_line = -1<br />
&nbsp;&nbsp;to_line = -1<br />
&nbsp;&nbsp;last_line = 0 # Last printed line.<br />
&nbsp;<br />
&nbsp;&nbsp;while 1:<br />
&nbsp;&nbsp;&nbsp;&nbsp;l = f.readline()<br />
&nbsp;&nbsp;&nbsp;&nbsp;line_nb += 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;if not l:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;match = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;if re.search(p, l):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from_line = line_nb - options.before_context<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to_line = line_nb + options.after_context<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;match = 1<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if line_nb &lt;= to_line:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if options.before_context or options.after_context:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if last_line and from_line &gt; last_line + 1:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.stdout.write(&quot;&#45;-\n&quot;)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from_line = max(from_line, last_line + 1, -len(queue))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for i in range(from_line - line_nb, 0):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if options.line_number:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.stdout.write(&quot;%d-&quot; % (i + line_nb))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.stdout.write(queue[i])<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if options.line_number:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if match:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.stdout.write(&quot;%d:&quot; % line_nb)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.stdout.write(&quot;%d-&quot; % line_nb)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys.stdout.write(l)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;last_line = line_nb<br />
&nbsp;&nbsp;&nbsp;&nbsp;queue.append(l)<br />
&nbsp;<br />
def printUsage():<br />
&nbsp;&nbsp;&quot;&quot;&quot;Print the help string that should printed by grep.py -h&quot;&quot;&quot;<br />
&nbsp;&nbsp;print &quot;usage: grep.py [options] pattern [file]&quot;<br />
&nbsp;&nbsp;print &quot;&quot;&quot;<br />
&nbsp;&nbsp;-i, &#45;-ignore-case&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ignore case distinctions<br />
&nbsp;&nbsp;-B, &#45;-before-context=NUM&nbsp;&nbsp;print NUM lines of leading context<br />
&nbsp;&nbsp;-A, &#45;-after-context=NUM&nbsp;&nbsp; print NUM lines of trailing context<br />
&nbsp;&nbsp;-C, &#45;-context[=NUM]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print NUM (default 2) lines of output context<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unless overridden by -A or -B<br />
&nbsp;&nbsp;-n, &#45;-line-number&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print line number with output lines<br />
&nbsp;&nbsp;-V, &#45;-version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print version information and exit<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#45;-help&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display this help and exit<br />
&nbsp;<br />
See http://www.vdesmedt.com/~vds2212/grep.html for informations and updates.<br />
Send an email to vivian@vdesmedt.com for comments and bug reports.&quot;&quot;&quot;<br />
&nbsp;<br />
def printVersion():<br />
&nbsp;&nbsp;print &quot;grep.py version 0.5.0&quot;<br />
&nbsp;<br />
class Options:<br />
&nbsp;&nbsp;def __init__(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.ignore_case = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.before_context = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.after_context = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.line_number = 0<br />
&nbsp;<br />
def main(argv):<br />
&nbsp;&nbsp;options = Options()<br />
&nbsp;<br />
&nbsp;&nbsp;opts, args = getopt.getopt(argv, &quot;ViA:B:C:n&quot;, [&quot;help&quot;, &quot;version&quot;, &quot;ignore-case&quot;, &quot;before-context=&quot;, &quot;after-context=&quot;, &quot;context=&quot;, &quot;line-number&quot;])<br />
&nbsp;&nbsp;for o, v in opts:<br />
&nbsp;&nbsp;&nbsp;&nbsp;if o in [&quot;-i&quot;, &quot;&#45;-ignore-case&quot;]:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options.ignore_case = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;if o in [&quot;-A&quot;, &quot;&#45;-after-context&quot;]:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options.after_context = int(v)<br />
&nbsp;&nbsp;&nbsp;&nbsp;if o in [&quot;-B&quot;, &quot;&#45;-before-context&quot;]:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options.before_context = int(v)<br />
&nbsp;&nbsp;&nbsp;&nbsp;if o in [&quot;-C&quot;, &quot;&#45;-context&quot;]:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if not v:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v = 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options.after_context = int(v)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options.before_context = int(v)<br />
&nbsp;&nbsp;&nbsp;&nbsp;if o in [&quot;-n&quot;, &quot;&#45;-line-number&quot;]:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options.line_number = 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;elif o in [&quot;-V&quot;, &quot;&#45;-version&quot;]:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printVersion()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;elif o in [&quot;&#45;-help&quot;]:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printUsage()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0<br />
&nbsp;<br />
&nbsp;&nbsp;if len(args) &lt;= 0:<br />
&nbsp;&nbsp;&nbsp;&nbsp;printUsage()<br />
&nbsp;&nbsp;&nbsp;&nbsp;return 1<br />
&nbsp;<br />
&nbsp;&nbsp;pattern = args[0]<br />
&nbsp;<br />
&nbsp;&nbsp;if len(args) == 1:<br />
&nbsp;&nbsp;&nbsp;&nbsp;return grep(pattern, sys.stdin, options)<br />
&nbsp;<br />
&nbsp;&nbsp;fileList = glob.glob(args[1])<br />
&nbsp;&nbsp;for fileName in fileList:<br />
&nbsp;&nbsp;&nbsp;&nbsp;f = open(fileName)<br />
&nbsp;&nbsp;&nbsp;&nbsp;print fileName + &quot; : &quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;r = grep(pattern, f, options)<br />
&nbsp;&nbsp;&nbsp;&nbsp;f.close()<br />
&nbsp;<br />
&nbsp;&nbsp;return r<br />
&nbsp;<br />
if __name__ == &quot;__main__&quot;:<br />
&nbsp;&nbsp;sys.exit(main(sys.argv[1:]))<br />
&nbsp;<br />
</code><br/></div>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/07/29/python-grep-script-with-multiple-files/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Debugging Ajax PHP with Logging and Firebug</title>
		<link>http://www.exfer.net/blog/2007/06/03/debugging-ajax-php-with-logging-and-firebug/</link>
		<comments>http://www.exfer.net/blog/2007/06/03/debugging-ajax-php-with-logging-and-firebug/#comments</comments>
		<pubDate>Sun, 03 Jun 2007 15:15:39 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/05/18/debugging-ajax-php-with-logging-and-firebug/</guid>
		<description><![CDATA[I was recently trying to debug some Ajax PHP code.  I was logging but it was cumbersome trying to look at both the php log file and Javascript logging in Firebug so I started going some searching.  I found post from Mika Tuupola about Debugging PHP With Firebug, so I took his advice [...]]]></description>
			<content:encoded><![CDATA[<p>I was recently trying to debug some Ajax PHP code.  I was logging but it was cumbersome trying to look at both the php log file and Javascript logging in Firebug so I started going some searching.  I found post from Mika Tuupola about <a href="http://www.appelsiini.net/~tuupola/312/debugging-php-with-firebug" target="_blank">Debugging PHP With Firebug</a>, so I took his advice and moved to the PEAR:Log package with a Firebug handler. </p>
<p>But I still had a problem since I was debugging Ajax requests.  The way the system works is it tacks on Javascript code to your page in a script tag that will be run when the page loads.  This is fine for a standard page but for an Ajax request the result isn&#8217;t run.  Basically the response would look something like this.</p>
<div class="quickcodenoclick"><code><br />
&lt;results&gt;<br />
&nbsp;&nbsp;&lt;result&gt;34&lt;/result&gt;<br />
&nbsp;&nbsp;&lt;result&gt;5&lt;/result&gt;<br />
&lt;/results&gt;<br />
&lt;script type=&quot;text/javascript&quot;&gt;<br />
&nbsp;&nbsp;console.log(&quot;there are 2 results&quot;);<br />
&lt;/script&gt;<br />
</code><br/></div>
<p>So all I did was write a function to strip out that Javascript code and execute it.  The code is here</p>
<div class="quickcodenoclick"><code><br />
exfer.extractDebugMessage = function (s) {<br />
&nbsp;&nbsp;var beginIndex = s.indexOf(&quot;&lt;script&quot;);<br />
&nbsp;<br />
&nbsp;&nbsp;if (beginIndex != -1) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;var str = s.substring(beginIndex); // extract the script tag at the end of the response<br />
&nbsp;&nbsp;&nbsp;&nbsp;str = str.replace(/\n/g, &quot;[N]&quot;); // converts carriage returns into &quot;[N]&quot; so the regular expression can work without the &quot;m&quot; option<br />
&nbsp;&nbsp;&nbsp;&nbsp;var result = str.match(new RegExp(&quot;&lt;script.*&gt;(.*)&lt;\/&quot; + &quot;script&gt;&quot;)); // get the code from the tag<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (result &amp;&amp; result[1]) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str = result[1].replace(/\[N\]/g, &quot;\n&quot;); // put the CRs back in<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (typeof console != &quot;undefined&quot;) { // if console is available execute the code<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eval(str);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;s = s.substring(0, beginIndex);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;return (s);<br />
}<br />
</code><br/></div>
<p>Then the code is called with the XMLHttpRequest responseText.</p>
<div class="quickcodenoclick"><code><br />
var realResponseText = exfer.extractDebugMessage(xhr.responseText);<br />
</code><br/></div>
<p>Which pulls out the debug message and executes it, then returns what is left over to be passed along.</p>
<p>There are potential holes in the code of course.  For example someone might have the string &#8220;&lt;script&#8221; in their Ajax response but since it&#8217;s a debugging tool I&#8217;m not too worried about it.  One quick note, since the code looks for the existence of console instead of Firebug it should also work with <a href="http://www.getfirebug.com/lite.html" target="_blank">Firebug Lite</a> although I haven&#8217;t yet tested it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/06/03/debugging-ajax-php-with-logging-and-firebug/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Enumerating Local Variables in JavaScript</title>
		<link>http://www.exfer.net/blog/2007/05/07/enumerating-local-variables-in-javascript/</link>
		<comments>http://www.exfer.net/blog/2007/05/07/enumerating-local-variables-in-javascript/#comments</comments>
		<pubDate>Mon, 07 May 2007 17:00:02 +0000</pubDate>
		<dc:creator>david_kw</dc:creator>
		
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.exfer.net/blog/2007/05/07/enumerating-local-variables-in-javascript/</guid>
		<description><![CDATA[One day I was trying to do some debugging in browsers other than FireFox (FireBug rocks and is highly recommended).  I decided it would be useful if I could enumerate local variables such that I could quickly find and display their values in an alert box.  Unfortunately, there didn&#8217;t appear to be any [...]]]></description>
			<content:encoded><![CDATA[<p>One day I was trying to do some debugging in browsers other than FireFox (<a href="http://www.getfirebug.com" target="_blank">FireBug rocks and is highly recommended</a>).  I decided it would be useful if I could enumerate local variables such that I could quickly find and display their values in an alert box.  Unfortunately, there didn&#8217;t appear to be any way to do that in some browsers.  So the solution I came up with was to parse the function text itself (which can be found with func.toString()) to find all the local variables.</p>
<p>Of course there are a couple problems with this method.  First of all my parsing is very limited.  I didn&#8217;t want to write a JavaScript interpreter.  Second, to get the values of the variables an evaluation function has to be passed in (trick found from <a href="http://trimpath.com/project/wiki/TrimBreakpoint" target="_blank">TrimBreakpoint</a>).  And I&#8217;m sure there are other problems I can&#8217;t think of at the moment. :)</p>
<p>Anyway, on to the example.  One of the interesting aspects of this method is the ability to see closure values from outside the function (click the third button in the example).  Use View Source to get the full source from the example.</p>
<p><a href="http://www.exfer.net/test/enumerate_local_variables.html" target="_blank">Example of Enumerate Local Variables</a></p>
<p><a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode161');">Example Calls to Show Locals</a></p>
<div id="quickcode161" class="quickcode"><code><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function doItInside(s) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var x = 5, y = 9;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var re = /^test$/;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (var i = 0; i &lt; 5; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var arr = [ 2, 4, 6, 8 ];<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (arr[i] == i) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var ob = { x: 7, y: 5 };<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showLocals(function($$$$){return(eval($$$$))}, arguments);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var outsideCheckerFunc;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function doItOutside(str_param, num_param) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var timer = 100;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outsideCheckerFunc = function($$$$){return(eval($$$$))};<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var f = function(){alert(&quot;hi&quot;)};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var a = 55, b = 66, c = 77;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var regE = new RegExp(&quot;^s*tart?&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function doItOutsideCaller(withEvalFunc) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (withEvalFunc) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doItOutside(&#039;test param string&#039;, 9);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showLocals(outsideCheckerFunc, doItOutside);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showLocals(null, doItOutside);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</code><br/></div>
]]></content:encoded>
			<wfw:commentRss>http://www.exfer.net/blog/2007/05/07/enumerating-local-variables-in-javascript/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
