<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2266387177743068088</id><updated>2011-09-16T08:53:06.211-05:00</updated><category term='pointers'/><category term='eee'/><category term='javascript'/><category term='unix'/><category term='gnu/linux'/><category term='reference'/><category term='mac'/><category term='debian'/><category term='benchmarking'/><category term='typeof'/><category term='instanceof'/><category term='types'/><category term='.NET'/><category term='null'/><title type='text'>elijahr</title><subtitle type='html'>notes on javascript, linux, and more</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-4447651714440761976</id><published>2009-11-11T09:22:00.010-06:00</published><updated>2009-11-11T16:16:05.049-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='typeof'/><category scheme='http://www.blogger.com/atom/ns#' term='null'/><category scheme='http://www.blogger.com/atom/ns#' term='reference'/><category scheme='http://www.blogger.com/atom/ns#' term='instanceof'/><category scheme='http://www.blogger.com/atom/ns#' term='pointers'/><title type='text'>typeof(null) and Pointers  in JavaScript</title><content type='html'>I had a bit of an epiphany this morning when I was trying to figure out why &lt;code&gt;typeof(null) === 'object'&lt;/code&gt; yields true.  If you have some value where &lt;code&gt;typeof(value) === "object"&lt;/code&gt; and you assign that value to a variable, that variable becomes a reference to that value.  If you have some value where &lt;code&gt;typeof(value) === "string" || typeof(value) === "number" || typeof(value) === "boolean"&lt;/code&gt;, and you assign that value to a variable, that variable now contains a copy of that value rather than a reference.  But sometimes,  &lt;code&gt;typeof(my_string_variable) === 'object'&lt;/code&gt;, and assigning that string variable to another variable will create a reference to, not a copy of, that variable's value.  Why is that, and why is &lt;code&gt;typeof(null) === 'object'&lt;/code&gt; true?&lt;br /&gt;&lt;br /&gt;First let's run through some examples to illustrate what I'm talking about.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;var&lt;br /&gt;a = 'a',&lt;br /&gt;b = a&lt;br /&gt;&lt;br /&gt;a.foo = 'bar'&lt;br /&gt;alert(b.foo) // alerts 'undefined'&lt;br /&gt;&lt;br /&gt;a = new Object()&lt;br /&gt;b = a&lt;br /&gt;&lt;br /&gt;a.foo = 'bar'&lt;br /&gt;alert(b.foo) // alerts 'bar'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;What if I want to create a pointer to a string, a number, or a boolean?&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;alert(typeof('a')) // alerts 'string'&lt;br /&gt;alert(typeof(true)) // alerts 'boolean'&lt;br /&gt;alert(typeof(1)) // alerts 'number'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So, assigning those values will result in a copy, not a reference.  But:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;alert(typeof(new String('a'))) // alerts 'object'&lt;br /&gt;alert(typeof(new Boolean(true))) // alerts 'object'&lt;br /&gt;alert(typeof(new Number(1))) // alerts 'object'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;What does this mean?  It means you can create pointers to JavaScript primitives.  This answers my first question.  If &lt;code&gt;typeof(value) === 'object'&lt;/code&gt; but value is a number, a string, or a boolean value, then you've got yourself a pointer to an object. If you want to assign your object's value to a variable, sans pointer, just use &lt;code&gt;value.valueOf()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;You can also check whether some value is a pointer or primitive using &lt;code&gt;instanceof&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;alert('a' instanceof String) // alerts false&lt;br /&gt;alert(true instanceof Boolean) // alerts false&lt;br /&gt;alert(1 instanceof Number) // alerts false&lt;br /&gt;alert(new String('a') instanceof String) // alerts true&lt;br /&gt;alert(new Boolean(true) instanceof Boolean) // alerts true&lt;br /&gt;alert(new Number(1) instanceof Number) // alerts true&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The below function makes it easy to point to primitive values.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;function point(value) { // return a pointer to some primitive value&lt;br /&gt; switch( typeof(value) ) {&lt;br /&gt;  case 'string': case 'number': case 'boolean':&lt;br /&gt;   return new value.constructor(value)&lt;br /&gt; }&lt;br /&gt; return value&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Use it like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;var&lt;br /&gt;my_string = point('a'),&lt;br /&gt;my_string_alias = my_string&lt;br /&gt; &lt;br /&gt;my_string.foo = 'bar'&lt;br /&gt;alert(my_string_alias.foo) // alerts 'bar'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;It should be noted, that if you pass a variable containing a primitive into &lt;code&gt;point&lt;/code&gt;, you will not get a pointer to that primitive; a new object will be created with the value you passed in.  Here's an example:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;var&lt;br /&gt;my_string = 'a',&lt;br /&gt;my_string_alias = point(my_string)&lt;br /&gt;&lt;br /&gt;my_string_alias.foo = 'bar'&lt;br /&gt;&lt;br /&gt;alert(my_string.foo) // alerts 'undefined'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;One way that this can be resolved is by a simple reassignment of the original variable to the new object:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;var&lt;br /&gt;my_string = 'a',&lt;br /&gt;my_string_alias = my_string = point(my_string)&lt;br /&gt;&lt;br /&gt;my_string_alias.foo = 'bar'&lt;br /&gt;&lt;br /&gt;alert(my_string.foo) // alerts 'bar'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Ok, so now that that has been cleared up, what about my second question: why is &lt;code&gt;typeof(null) === 'object'&lt;/code&gt; true?  The only thing I can think is that &lt;code&gt;null&lt;/code&gt; is a pointer, not a primitive value, and that when &lt;code&gt;typeof&lt;/code&gt; returns 'object', it means that the passed in value is a pointer, not a primitive value.  Perhaps when I have some time I'll download the TraceMonkey source and grep through the logic in &lt;code&gt;typeof&lt;/code&gt; to verify this, but its the best explanation I've found thus far; many JavaScripters seem to consider &lt;code&gt;typeof&lt;/code&gt; broken because it returns "object" when a null value is passed in.  What's the use all of this information?  Well, one use is that we can use this knowledge to check if some value is iterable:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;function is_iterable ( value ) {&lt;br /&gt; return value !== null &amp;&amp; typeof( value ) === 'object'&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If &lt;code&gt;is_iterable&lt;/code&gt; returns true for some variable or value that you pass in, you are assured that &lt;code&gt;for (var x in value)&lt;/code&gt; loops and &lt;code&gt;x in value&lt;/code&gt; statements on that value will execute without throwing a &lt;code&gt;TypeError&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I'm sure more knowledgeable JavaScripters than I might take all of this information for granted, but I was unable to find any informed resources on this particular subject in my googlings.  I hope that you've found it useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-4447651714440761976?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/4447651714440761976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=4447651714440761976' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4447651714440761976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4447651714440761976'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/11/types-pointers-in-javascript.html' title='typeof(null) and Pointers  in JavaScript'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-3660831997095709480</id><published>2009-05-06T11:48:00.009-05:00</published><updated>2009-06-10T06:54:50.584-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Multiple Class Inheritance with Prototypes in Javascript</title><content type='html'>Here is a simple example to demonstrate &lt;a href="http://en.wikipedia.org/wiki/Multiple_inheritance"&gt;multiple class inheritance&lt;/a&gt; in Javascript.  Let's say we are trying to describe a dog named Lily who is is a pit bull &amp; black labrador mix.  We can do this by combining a Dog class, a PitBull class, and a BlackLabrador class into a PitLabMix class.  &lt;a href="http://en.wikipedia.org/wiki/Prototype-based_programming"&gt;Prototyping&lt;/a&gt; splits the constructor from the class template, which allows us to inherit from several classes without having to instantiate any of them.  In the end, we have an instance of the PitLabMix class named 'lily', which has all the properties of Dog, PitBull, and BlackLabrador.  The script makes use of the &lt;code&gt;window.console.log&lt;/code&gt; function in &lt;a href="http://getfirebug.com/"&gt;Firebug&lt;/a&gt; to demonstrate what the final object looks like.  For non-Firefox browsers, there is also &lt;a href="http://getfirebug.com/lite.html"&gt;Firebug Lite&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;function Dog (name) {&lt;br /&gt;  this.name = name;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Dog.prototype = {&lt;br /&gt;  kingdom : "Animalia",&lt;br /&gt;  subkingdom : "Eumetazoa",&lt;br /&gt;  phylum : "Chordata",&lt;br /&gt;  subphylum : "Vertebrata",&lt;br /&gt;  class : "Mammalia",&lt;br /&gt;  subclass : "Theria",&lt;br /&gt;  order : "Carnivora",&lt;br /&gt;  suborder : "Caniformia",&lt;br /&gt;  family : "Canidae",&lt;br /&gt;  subfamily : "Caninae",&lt;br /&gt;  tribe : "Canini",&lt;br /&gt;  genus : "Canis",&lt;br /&gt;  species : "C. lupus",&lt;br /&gt;  subspecies : "C. l. familiaris"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function PitBull (name) {&lt;br /&gt;  this.name = name;&lt;br /&gt;  for (var x in Dog.prototype)&lt;br /&gt;    this[x] = Dog.prototype[x];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;PitBull.prototype = {&lt;br /&gt;  build : "Muscular",&lt;br /&gt;  demeanor : "Loyal"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function BlackLabrador (name) {&lt;br /&gt;  this.name = name;&lt;br /&gt;  for (var x in Dog.prototype)&lt;br /&gt;    this[x] = Dog.prototype[x];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;BlackLabrador.prototype = {&lt;br /&gt;  "fur color" : "Black"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function PitLabMix (name) {&lt;br /&gt;  this.name = name;&lt;br /&gt;  for (var x in Dog.prototype)&lt;br /&gt;    this[x] = Dog.prototype[x];&lt;br /&gt;  for (var x in PitBull.prototype)&lt;br /&gt;    this[x] = PitBull.prototype[x];&lt;br /&gt;  for (var x in BlackLabrador.prototype)&lt;br /&gt;    this[x] = BlackLabrador.prototype[x];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var lily = new PitLabMix('Lily');&lt;br /&gt;window.console.log(lily);&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-3660831997095709480?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/3660831997095709480/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=3660831997095709480' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3660831997095709480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3660831997095709480'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/05/class-inheritance-with-multiple-parent.html' title='Multiple Class Inheritance with Prototypes in Javascript'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-5060608169082639213</id><published>2009-04-13T18:16:00.011-05:00</published><updated>2009-04-22T13:03:34.083-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>A simple general-purpose Lexer written in JavaScript</title><content type='html'>If you need to tokenize a string, this code might come in handy.  Just modify the regular expressions in 'definitions' to suit your needs.&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;&lt;br /&gt;/*&lt;br /&gt;Copyright (c) 2009 Elijah Rutschman &amp;lt;elijahr@gmail.com&amp;gt;&lt;br /&gt;&lt;br /&gt;Permission is hereby granted, free of charge, to any person obtaining&lt;br /&gt;a copy of this software and associated documentation files (the&lt;br /&gt;"Software"), to deal in the Software without restriction, including&lt;br /&gt;without limitation the rights to use, copy, modify, merge, publish,&lt;br /&gt;distribute, sublicense, and/or sell copies of the Software, and to&lt;br /&gt;permit persons to whom the Software is furnished to do so, subject to&lt;br /&gt;the following conditions:&lt;br /&gt;&lt;br /&gt;The above copyright notice and this permission notice shall be&lt;br /&gt;included in all copies or substantial portions of the Software.&lt;br /&gt;&lt;br /&gt;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,&lt;br /&gt;EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF&lt;br /&gt;MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND&lt;br /&gt;NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE&lt;br /&gt;LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION&lt;br /&gt;OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION&lt;br /&gt;WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;  var definitions = {&lt;br /&gt;    identifier :        { regexp : /^[a-zA-Z]+[a-zA-Z0-9]*$/,      skip : false },&lt;br /&gt;    string :            { regexp : /^\"[^\"]*\"|\'[^\']*\'$/,      skip : false },&lt;br /&gt;    decimal_integer :   { regexp : /^[1-9]*\d+$/,                  skip : false },&lt;br /&gt;    left_parenthesis :  { regexp : /^\($/,                         skip : false },&lt;br /&gt;    right_parenthesis : { regexp : /^\)$/,                         skip : false },&lt;br /&gt;    comma :             { regexp : /^,$/,                          skip : false },&lt;br /&gt;    whitespace :        { regexp : /^[\t \n]$/,                    skip : true  }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  var Lexer = function ( string ) {&lt;br /&gt;    var index = 0;&lt;br /&gt;    var length = 1;&lt;br /&gt;    var arrayPosition = -1;&lt;br /&gt;    var _Lexer = this;&lt;br /&gt;    _Lexer.tokens = [];&lt;br /&gt;    _Lexer.lexemes = [];&lt;br /&gt;    _Lexer.token = null;&lt;br /&gt;    _Lexer.lexeme = null;&lt;br /&gt;    _Lexer.bof = true;&lt;br /&gt;    _Lexer.eof = false;&lt;br /&gt;    _Lexer.line_number = 0;&lt;br /&gt;    _Lexer.char_position = 0;&lt;br /&gt;    &lt;br /&gt;    // fill tokens and lexemes&lt;br /&gt;    while ( index + length &amp;lt;= string.length ) {&lt;br /&gt;      var small = string.substr( index, length ) ;&lt;br /&gt;      var big = string.substr( index, length + 1 ) ;&lt;br /&gt;      for ( var def in definitions ) {&lt;br /&gt;        var smallmatch = small.match( definitions[def].regexp ) !== null;&lt;br /&gt;        var bigmatch = big.match( definitions[def].regexp ) !== null;&lt;br /&gt;        if ( smallmatch &amp;&amp;( ! bigmatch || small == big )  ) {&lt;br /&gt;          // found a token&lt;br /&gt;          index += length;&lt;br /&gt;          length = 0;&lt;br /&gt;          _Lexer.tokens.push(def);&lt;br /&gt;          _Lexer.lexemes.push(small);&lt;br /&gt;          break;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      length++;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    _Lexer.next = function (count) {&lt;br /&gt;      if (count == undefined) count = 1;&lt;br /&gt;      while (count-- &amp;gt; 0) {&lt;br /&gt;        arrayPosition++;&lt;br /&gt;        if ( arrayPosition &amp;lt; _Lexer.tokens.length) {&lt;br /&gt;          _Lexer.token = _Lexer.tokens[arrayPosition];&lt;br /&gt;          _Lexer.lexeme = _Lexer.lexemes[arrayPosition];&lt;br /&gt;          _Lexer.bof = false;&lt;br /&gt;          _Lexer.char_position += _Lexer.lexeme.length;&lt;br /&gt;          if (definitions[_Lexer.token].skip) {&lt;br /&gt;            if (_Lexer.token == 'newline') {&lt;br /&gt;              _Lexer.line_number++;&lt;br /&gt;              _Lexer.char_position = 0;&lt;br /&gt;            }&lt;br /&gt;            _Lexer.next();&lt;br /&gt;          }&lt;br /&gt;        } else {&lt;br /&gt;          _Lexer.token = 'EOF';&lt;br /&gt;          _Lexer.lexeme = null;&lt;br /&gt;          _Lexer.eof = true;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    _Lexer.prev = function (count) {&lt;br /&gt;      if (count == undefined) count = 1;&lt;br /&gt;      while (count-- &amp;gt; 0) {&lt;br /&gt;        arrayPosition--;&lt;br /&gt;        if ( arrayPosition-- &amp;gt; 0) {&lt;br /&gt;          _Lexer.token = _Lexer.tokens[arrayPosition];&lt;br /&gt;          _Lexer.lexeme = _Lexer.lexemes[arrayPosition];&lt;br /&gt;          _Lexer.eof = false;&lt;br /&gt;          _Lexer.char_position -= _Lexer.lexeme.length;&lt;br /&gt;          if (definitions[_Lexer.token].skip) {&lt;br /&gt;            if (_Lexer.token == 'newline') {&lt;br /&gt;              _Lexer.line_number--;&lt;br /&gt;              _Lexer.char_position = 0;&lt;br /&gt;            }&lt;br /&gt;            _Lexer.prev();&lt;br /&gt;          }&lt;br /&gt;        } else {&lt;br /&gt;          _Lexer.token = 'BOF';&lt;br /&gt;          _Lexer.lexeme = null;&lt;br /&gt;          _Lexer.bof = true;&lt;br /&gt;          break;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  var lexer = new Lexer("hello('world', 2)");&lt;br /&gt;  while (! lexer.eof ) {&lt;br /&gt;   lexer.next()&lt;br /&gt;   document.write( lexer.token + ' ' );&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;This will output "identifier left_parenthesis string comma decimal_integer right_parenthesis EOF" to the page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-5060608169082639213?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/5060608169082639213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=5060608169082639213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/5060608169082639213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/5060608169082639213'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/04/lexer-written-in-javascript.html' title='A simple general-purpose Lexer written in JavaScript'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-4067958784319845154</id><published>2009-04-06T18:06:00.004-05:00</published><updated>2009-04-06T18:16:46.840-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Mirror - A Two-sided Dictionary for Javascript</title><content type='html'>I was playing around and came up with this class for "two-sided" dictionaries, meaning that there is no differentiation between keys and values.&lt;br /&gt;&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;&lt;br /&gt;var Mirror = function () {&lt;br /&gt;  this.couples = [];&lt;br /&gt;};&lt;br /&gt;Mirror.prototype.place = function (x, y) {&lt;br /&gt;  if (x == undefined) x = null;&lt;br /&gt;  if (y == undefined) y = null;&lt;br /&gt;  &lt;br /&gt;  if (this.reflect(x) != undefined)&lt;br /&gt;    this.dissolve(x);&lt;br /&gt;  if (this.reflect(y) != undefined)&lt;br /&gt;    this.dissolve(y);&lt;br /&gt;  &lt;br /&gt;  this.couples.push([x,y]);&lt;br /&gt;};&lt;br /&gt;Mirror.prototype.dissolve = function(key) {&lt;br /&gt;  for (var i = 0; i&amp;lt;this.couples.length; i++ ) {&lt;br /&gt;    for (var j = 0; j&amp;lt;2; j++ ) {&lt;br /&gt;      if (this.couples[i][j] === key) {&lt;br /&gt;        this.couples.splice(i,1);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;Mirror.prototype.reflect = function (key) {&lt;br /&gt;  for (var i = 0; i&amp;lt;this.couples.length; i++ ) {&lt;br /&gt;    for (var j = 0; j&amp;lt;2; j++ ) {&lt;br /&gt;      if (this.couples[i][j] === key) {&lt;br /&gt;        return this.couples[i][j ^ 1];&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;var mirror = new Mirror();&lt;br /&gt;// place items in the Mirror&lt;br /&gt;mirror.place("johnny", "mark");&lt;br /&gt;mirror.place("sammy", "sarah");&lt;br /&gt;mirror.place("andrew", "engelbert");&lt;br /&gt;mirror.place("yasha", "katrina");&lt;br /&gt;&lt;br /&gt;// get the 'mate' for the key you pass in&lt;br /&gt;mirror.reflect("katrina"); // yasha&lt;br /&gt;mirror.reflect("engelbert"); // andrew&lt;br /&gt;mirror.reflect("sammy"); // sarah&lt;br /&gt;&lt;br /&gt;// uh oh! scandal&lt;br /&gt;mirror.place("engelbert", "sarah");&lt;br /&gt;&lt;br /&gt;// where did they go?&lt;br /&gt;mirror.reflect("sammy"); // undefined, he's out of the picture.&lt;br /&gt;mirror.reflect("andrew"); // undefined, he's out of the picture.&lt;br /&gt;&lt;br /&gt;mirror.reflect("engelbert"); // sarah&lt;br /&gt;mirror.reflect("sarah"); // engelbert&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-4067958784319845154?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/4067958784319845154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=4067958784319845154' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4067958784319845154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4067958784319845154'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/04/mirror-two-sided-dictionary-for.html' title='Mirror - A Two-sided Dictionary for Javascript'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-8773300706695388085</id><published>2009-03-30T13:44:00.010-05:00</published><updated>2009-03-31T08:58:53.107-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Cron for Javascript</title><content type='html'>This class provides some simple scheduling with callbacks.&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;/*  Copyright (C) 2009 Elijah Rutschman&lt;br /&gt;&lt;br /&gt;    This program is free software: you can redistribute it and/or modify&lt;br /&gt;    it under the terms of the GNU General Public License as published by&lt;br /&gt;    the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;    any later version.&lt;br /&gt;&lt;br /&gt;    This program is distributed in the hope that it will be useful,&lt;br /&gt;    but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;    GNU General Public License for more details, available at&lt;br /&gt;    &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;a typical cron entry has either wildcards (*) or an integer:&lt;br /&gt;&lt;br /&gt; .---------------- minute (0 - 59) &lt;br /&gt; |  .------------- hour (0 - 23)&lt;br /&gt; |  |  .---------- day of month (1 - 31)&lt;br /&gt; |  |  |  .------- month (1 - 12)&lt;br /&gt; |  |  |  |  .---- day of week (0 - 6) (Sunday=0)&lt;br /&gt; |  |  |  |  |&lt;br /&gt; *  *  *  *  *&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;var Cron = {&lt;br /&gt; "jobs" : [],&lt;br /&gt; "process" : function() {&lt;br /&gt;  var now = new Date();&lt;br /&gt;  for (var i=0; i&amp;lt;Cron.jobs.length; i++) {&lt;br /&gt;   if ( Cron.jobs[i].minute == "*" || parseInt(Cron.jobs[i].minute) == now.getMinutes() )&lt;br /&gt;    if ( Cron.jobs[i].hour == "*" || parseInt(Cron.jobs[i].hour) == now.getHours() )&lt;br /&gt;     if ( Cron.jobs[i].date == "*" || parseInt(Cron.jobs[i].date) == now.getDate() )&lt;br /&gt;      if ( Cron.jobs[i].month == "*" || (parseInt(Cron.jobs[i].month) - 1) == now.getMonth() )&lt;br /&gt;       if ( Cron.jobs[i].day == "*" || parseInt(Cron.jobs[i].day) == now.getDay() )&lt;br /&gt;        Cron.jobs[i].run();&lt;br /&gt;  }&lt;br /&gt;  now = null;&lt;br /&gt; },&lt;br /&gt; "id" : 0,&lt;br /&gt; "start" : function() {&lt;br /&gt;  Cron.stop();&lt;br /&gt;  Cron.id = setInterval("Cron.process()",60000);&lt;br /&gt; },&lt;br /&gt; "stop" : function() {&lt;br /&gt;  clearInterval(Cron.id);&lt;br /&gt; },&lt;br /&gt; "Job" : function(cronstring, fun) {&lt;br /&gt;  var _Job = this;&lt;br /&gt;  var items = cronstring.match(/^([0-9]+|\*{1})[ \n\t\b]+([0-9]+|\*{1})[ \n\t\b]+([0-9]+|\*{1})[ \n\t\b]+([0-9]+|\*{1})[ \n\t\b]+([0-9]+|\*{1})[ \n\t\b]*$/);&lt;br /&gt;  _Job.minute = items[1];&lt;br /&gt;  _Job.hour = items[2];&lt;br /&gt;  _Job.date = items[3];&lt;br /&gt;  _Job.month = items[4];&lt;br /&gt;  _Job.day = items[5];&lt;br /&gt;  _Job.run = fun;&lt;br /&gt;  Cron.jobs.push(_Job);&lt;br /&gt;  _Job = null;&lt;br /&gt;  items = null;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// queue up some jobs to run&lt;br /&gt;var j1 = new Cron.Job("* * * * *", function(){alert('cron job 1 just ran')})&lt;br /&gt;var j2 = new Cron.Job("5 * * * *", function(){alert('cron job 2 just ran')})&lt;br /&gt;var j3 = new Cron.Job("15 * * * *", function(){alert('cron job 3 just ran')})&lt;br /&gt;var j4 = new Cron.Job("30 * * * *", function(){alert('cron job 4 just ran')})&lt;br /&gt;Cron.start();&lt;br /&gt;&lt;br /&gt;// Cron already running, but we can add more jobs, no problem&lt;br /&gt;var j5 = new Cron.Job("0 * * * *", function(){alert('cron job 5 just ran')})&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-8773300706695388085?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/8773300706695388085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=8773300706695388085' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/8773300706695388085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/8773300706695388085'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/03/javascript-cron.html' title='Cron for Javascript'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-4248658234493887375</id><published>2009-03-27T14:32:00.004-05:00</published><updated>2009-03-27T14:53:09.323-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='benchmarking'/><title type='text'>Simple Javascript Benchmarking Class</title><content type='html'>&lt;pre class="javascript" name="code"&gt;var Benchmark = function( testee, iterations ) {&lt;br /&gt;    var _Benchmark = this;&lt;br /&gt;    _Benchmark.testee = testee;&lt;br /&gt;    _Benchmark.iterations = iterations || 1;&lt;br /&gt;    _Benchmark.time = -1;&lt;br /&gt;    _Benchmark.runtime = -1;&lt;br /&gt;    &lt;br /&gt;    _Benchmark.run = function() {&lt;br /&gt;        var time = 0;&lt;br /&gt;        for (var i=0; i&amp;lt;_Benchmark.iterations; i++) {&lt;br /&gt;            var startTime = new Date();&lt;br /&gt;            _Benchmark.testee();&lt;br /&gt;            var endTime = new Date();&lt;br /&gt;            time += endTime - startTime;            &lt;br /&gt;        }&lt;br /&gt;        _Benchmark.runtime = time;&lt;br /&gt;        _Benchmark.time = time / iterations;&lt;br /&gt;    };&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;How to use it:&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;function nothing(x) {&lt;br /&gt;    // does a bunch of nothing&lt;br /&gt;    if (x &amp;gt; 0)&lt;br /&gt;        var y = (Math.sqrt(x) * Math.sqrt(nothing(x - 1)));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var myBenchmark = new Benchmark(function(){nothing(10)}, 300);&lt;br /&gt;myBenchmark.run();&lt;br /&gt;alert("Average run time to do nothing: " + myBenchmark.time );&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-4248658234493887375?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/4248658234493887375/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=4248658234493887375' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4248658234493887375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4248658234493887375'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/03/simple-javascript-benchmarking-class.html' title='Simple Javascript Benchmarking Class'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-1773240504054908956</id><published>2009-03-10T22:04:00.002-05:00</published><updated>2009-03-10T22:14:32.943-05:00</updated><title type='text'>Dvorak</title><content type='html'>I am typing using a Dvorak layout.  It is difficult.  My typing speed has been reduced drastically.  So why Dvorak?  It is supposed to eventually get better.  Unfortunately, this message has thus far taken 5 minutes to type.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-1773240504054908956?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/1773240504054908956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=1773240504054908956' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/1773240504054908956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/1773240504054908956'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/03/dvorak.html' title='Dvorak'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-6397444451797020297</id><published>2009-01-15T10:28:00.006-06:00</published><updated>2009-01-15T10:34:17.226-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Escaping characters between Javascript and .NET</title><content type='html'>In .NET, the most robust escape function for special characters is &lt;cmd&gt;Server.UrlEncode&lt;/cmd&gt;.  In Javascript, it is said that this is compatible with &lt;cmd&gt;encodeURIComponent&lt;/cmd&gt;.  However, I found two discrepancies: the "~" character and the space character.  Here's a Javascript snippet you can use to escape things in a manner compatible with .NET:&lt;br /&gt;&lt;pre class="javascript" name="code"&gt;urlDecode = function (text) {&lt;br /&gt;/*&lt;br /&gt;    description:&lt;br /&gt;        - javascript equivalent of .NET's Server.UrlDecode&lt;br /&gt;*/&lt;br /&gt;    return decodeURIComponent(text.replace(/\+/g,'%20').replace(/%7e/g,'~'));&lt;br /&gt;}&lt;br /&gt;urlEncode = function (text) {&lt;br /&gt;/*&lt;br /&gt;    description:&lt;br /&gt;        - javascript equivalent of .NET's Server.UrlEncode&lt;br /&gt;*/&lt;br /&gt;    return encodeURIComponent(text).replace(/%20/g,'+').replace(/~/g,'%7e');&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-6397444451797020297?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/6397444451797020297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=6397444451797020297' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/6397444451797020297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/6397444451797020297'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2009/01/escaping-characters-between-javascript.html' title='Escaping characters between Javascript and .NET'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-6952462609662949439</id><published>2008-12-26T11:03:00.011-06:00</published><updated>2008-12-28T18:56:24.130-06:00</updated><title type='text'>Zenburn Blogger Template with Syntax Highlighting for Code Examples</title><content type='html'>I love the &lt;a href="http://slinky.imukuppi.org/zenburn/"&gt;Zenburn&lt;/a&gt; color scheme.  I use it for vim, xterm, Visual Studio, PuTTY, Notepad++.  Its really easy to look at all day, much nicer than a high contrast color scheme like black text on a white background.  So, I decided to make my blogger template look like Zenburn.  I recommend that you load the &lt;a href='http://code.google.com/p/syntaxhighlighter/'&gt;&lt;cmd&gt;SyntaxHighlighter&lt;/cmd&gt;&lt;/a&gt; scripts from a server under your control just in case I move my scripts later.  Here is the template if you are interested in using it:&lt;br /&gt;&lt;br /&gt;&lt;pre class='html' name='code'&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; ?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Strict//EN&amp;quot; &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;html expr:dir='data:blog.languageDirection' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;meta content='HTML Tidy for Linux/x86 (vers 11 February 2007), see www.w3.org' name='generator'/&amp;gt;&lt;br /&gt;&amp;lt;b:include data='blog' name='all-head-content'/&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;&amp;lt;data:blog.pageTitle/&amp;gt;&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;b:skin&amp;gt;&amp;lt;![CDATA[&lt;br /&gt;/*&lt;br /&gt;  * Blogger Template Style&lt;br /&gt;  *&lt;br /&gt;  * Simple Zenburn&lt;br /&gt;  * October 2008 - elijah rutschman&lt;br /&gt;  * based on Simple II by Jason Sutter&lt;br /&gt;  * and zenburn.vim by Jani Nurminen&lt;br /&gt;  */&lt;br /&gt;&lt;br /&gt; /* Variable definitions&lt;br /&gt;    ====================&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;bgcolor&amp;quot; description=&amp;quot;Page Background Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#444&amp;quot; value=&amp;quot;#3f3f3f&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;textcolor&amp;quot; description=&amp;quot;Text Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#eed&amp;quot; value=&amp;quot;#dcdccc&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;pagetitlecolor&amp;quot; description=&amp;quot;Blog Title Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#eed&amp;quot; value=&amp;quot;#dcdccc&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;titlecolor&amp;quot; description=&amp;quot;Post Title Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#eb9&amp;quot; value=&amp;quot;#dfaf8f&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;footercolor&amp;quot; description=&amp;quot;Date and Footer Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#8A8&amp;quot; value=&amp;quot;#7f9f7f&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;linkcolor&amp;quot; description=&amp;quot;Link Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#9dd&amp;quot; value=&amp;quot;#8cd0d3&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;visitedlinkcolor&amp;quot; description=&amp;quot;Visited Link Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#9ee&amp;quot; value=&amp;quot;#93e0e3&amp;quot;&amp;gt; Used to be #969&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;bordercolor&amp;quot; description=&amp;quot;Border Color&amp;quot;&lt;br /&gt;     type=&amp;quot;color&amp;quot; default=&amp;quot;#c99&amp;quot; value=&amp;quot;#cc9393&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;bodyfont&amp;quot; description=&amp;quot;Text Font&amp;quot;&lt;br /&gt;     type=&amp;quot;font&amp;quot; default=&amp;quot;normal normal 80% Trebuchet MS, Verdana, Arial, Sans-serif&amp;quot;&lt;br /&gt;     value=&amp;quot;normal normal 80% Trebuchet MS, Verdana,Arial, Sans-serif&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;pagetitlefont&amp;quot; description=&amp;quot;Blog Title Font&amp;quot;&lt;br /&gt;     type=&amp;quot;font&amp;quot;&lt;br /&gt;     default=&amp;quot;normal bold 150% Trebuchet MS, Verdana, Arial, Sans-serif&amp;quot;&lt;br /&gt;     value=&amp;quot;normal bold 150% Trebuchet MS, Verdana, Arial, Sans-serif&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;codefont&amp;quot; description=&amp;quot;Code Example Font&amp;quot;&lt;br /&gt;     type=&amp;quot;font&amp;quot;&lt;br /&gt;     default=&amp;quot;normal normal 90% Monaco, Bitstream Vera Sans Mono, Lucida Sans Typewriter, monospace&amp;quot;&lt;br /&gt;     value=&amp;quot;normal normal 90% Monaco, Bitstream Vera Sans Mono, Lucida Sans Typewriter, monospace&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;startSide&amp;quot; description=&amp;quot;Start side in blog language&amp;quot;&lt;br /&gt;     type=&amp;quot;automatic&amp;quot; default=&amp;quot;left&amp;quot; value=&amp;quot;left&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Variable name=&amp;quot;endSide&amp;quot; description=&amp;quot;End side in blog language&amp;quot;&lt;br /&gt;     type=&amp;quot;automatic&amp;quot; default=&amp;quot;right&amp;quot; value=&amp;quot;right&amp;quot;&amp;gt;&lt;br /&gt; */&lt;br /&gt;body {&lt;br /&gt;    margin:0;&lt;br /&gt;    font:$bodyfont;&lt;br /&gt;    background:$bgcolor;&lt;br /&gt;    color:$textcolor;&lt;br /&gt;}&lt;br /&gt;a:link {&lt;br /&gt;    color:$linkcolor;&lt;br /&gt;    text-decoration:none;&lt;br /&gt;}&lt;br /&gt;a:visited {&lt;br /&gt;    color:$visitedlinkcolor;&lt;br /&gt;    text-decoration:none;&lt;br /&gt;}&lt;br /&gt;a:hover {&lt;br /&gt;    color:$titlecolor;&lt;br /&gt;    text-decoration:underline;&lt;br /&gt;}&lt;br /&gt;a img {&lt;br /&gt;    border-width:0;&lt;br /&gt;}&lt;br /&gt;#outer-wrapper {&lt;br /&gt;    margin-top: 0px;&lt;br /&gt;    margin-$endSide: 3em;&lt;br /&gt;    margin-bottom: 0;&lt;br /&gt;    margin-$startSide: 3em;&lt;br /&gt;}&lt;br /&gt;h1 {&lt;br /&gt;    border-bottom:dotted 1px $bordercolor;&lt;br /&gt;    margin-bottom:0px;&lt;br /&gt;    color: $pagetitlecolor;&lt;br /&gt;    font: $pagetitlefont;&lt;br /&gt;}&lt;br /&gt;h1 a, h1 a:link, h1 a:visited {&lt;br /&gt;    color: $pagetitlecolor;&lt;br /&gt;}&lt;br /&gt;h2 {&lt;br /&gt;    margin:0px;&lt;br /&gt;    padding: 0px;&lt;br /&gt;}&lt;br /&gt;blockquote, cmd, code {&lt;br /&gt;    color: $bordercolor;&lt;br /&gt;    font: $codefont;&lt;br /&gt;}&lt;br /&gt;#main .widget {&lt;br /&gt;    padding-bottom:10px;&lt;br /&gt;    margin-bottom:20px;&lt;br /&gt;    border-bottom:dotted 1px $bordercolor;&lt;br /&gt;    clear: both;&lt;br /&gt;}&lt;br /&gt;#main .Header {&lt;br /&gt;    border-bottom-width: 0px;&lt;br /&gt;}&lt;br /&gt;h2.date-header {&lt;br /&gt;    padding-top:15px;&lt;br /&gt;    color:$footercolor;&lt;br /&gt;    padding-bottom:0px;&lt;br /&gt;    margin-bottom:0px;&lt;br /&gt;    font-size: 90%;&lt;br /&gt;}&lt;br /&gt;h3.post-title {&lt;br /&gt;    font-size: 140%;&lt;br /&gt;    color: $titlecolor;&lt;br /&gt;}&lt;br /&gt;.post {&lt;br /&gt;    padding-$startSide:5%;&lt;br /&gt;    padding-$endSide:10%;&lt;br /&gt;}&lt;br /&gt;.post-footer {&lt;br /&gt;    color:$footercolor;&lt;br /&gt;}&lt;br /&gt;#comments {&lt;br /&gt;    padding-top:30px;&lt;br /&gt;    color:$textcolor;&lt;br /&gt;    padding-bottom:0px;&lt;br /&gt;    margin-bottom:0px;&lt;br /&gt;    font-weight:bold;&lt;br /&gt;}&lt;br /&gt;#comments .comment-footer {&lt;br /&gt;    font-size:1em;&lt;br /&gt;    font-weight:normal;&lt;br /&gt;    color:$footercolor;&lt;br /&gt;    margin-$endSide:10px;&lt;br /&gt;    display:inline;&lt;br /&gt;}&lt;br /&gt;.comment-author {&lt;br /&gt;    margin-top: 3%;&lt;br /&gt;}&lt;br /&gt;.comment-body {&lt;br /&gt;    font-size:1em;&lt;br /&gt;    font-weight:normal;&lt;br /&gt;}&lt;br /&gt;.deleted-comment {&lt;br /&gt;    font-style:italic;&lt;br /&gt;    color:gray;&lt;br /&gt;}&lt;br /&gt;.comment-link {&lt;br /&gt;    margin-$startSide:.6em;&lt;br /&gt;}&lt;br /&gt;.feed-links {&lt;br /&gt;    clear: both;&lt;br /&gt;    line-height: 2.5em;&lt;br /&gt;}&lt;br /&gt;#blog-pager-newer-link {&lt;br /&gt;    float: $startSide;&lt;br /&gt;}&lt;br /&gt;#blog-pager-older-link {&lt;br /&gt;    float: $endSide;&lt;br /&gt;}&lt;br /&gt;#blog-pager {&lt;br /&gt;    text-align: center;&lt;br /&gt;}&lt;br /&gt;.clear {&lt;br /&gt;    clear: both;&lt;br /&gt;}&lt;br /&gt;.profile-img {&lt;br /&gt;    float: $startSide;&lt;br /&gt;    margin-top: 0;&lt;br /&gt;    margin-$endSide: 5px;&lt;br /&gt;    margin-bottom: 5px;&lt;br /&gt;    margin-$startSide: 0;&lt;br /&gt;}&lt;br /&gt;body#layout #outer-wrapper {&lt;br /&gt;    margin-top: 0px;&lt;br /&gt;    margin-$endSide: 50px;&lt;br /&gt;    margin-bottom: 0;&lt;br /&gt;    margin-$startSide: 50px;&lt;br /&gt;}&lt;br /&gt;]]&amp;gt;&amp;lt;/b:skin&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;  &amp;lt;div id='outer-wrapper'&amp;gt;&lt;br /&gt; &amp;lt;b:section class='main' id='main' showaddelement='yes'&amp;gt;&lt;br /&gt;&amp;lt;b:widget id='Header1' locked='false' title='elijahr (Header)' type='Header'/&amp;gt;&lt;br /&gt;&amp;lt;b:widget id='BlogArchive1' locked='false' title='Blog Archive' type='BlogArchive'/&amp;gt;&lt;br /&gt;&amp;lt;b:widget id='Blog1' locked='true' title='Blog Posts' type='Blog'/&amp;gt;&lt;br /&gt;&amp;lt;b:widget id='Profile1' locked='false' title='About Me' type='Profile'/&amp;gt;&lt;br /&gt;&amp;lt;b:widget id='Label1' locked='false' title='Labels' type='Label'/&amp;gt;&lt;br /&gt;&amp;lt;b:widget id='LinkList1' locked='false' title='links' type='LinkList'/&amp;gt;&lt;br /&gt;&amp;lt;/b:section&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;script src='http://www.weekl.net/dp.SyntaxHighlighter/Scripts/shCore.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://www.weekl.net/dp.SyntaxHighlighter/Scripts/shBrushPython.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://www.weekl.net/dp.SyntaxHighlighter/Scripts/shBrushXml.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://www.weekl.net/dp.SyntaxHighlighter/Scripts/shBrushPhp.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://www.weekl.net/dp.SyntaxHighlighter/Scripts/shBrushJScript.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://www.weekl.net/dp.SyntaxHighlighter/Scripts/shBrushCss.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script type='text/javascript'&amp;gt;&lt;br /&gt;//&amp;lt;![CDATA[&lt;br /&gt;    dp.SyntaxHighlighter.BloggerMode();&lt;br /&gt;    dp.SyntaxHighlighter.HighlightAll('code');&lt;br /&gt;//]]&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&amp;lt;style type='text/css'&amp;gt;&lt;br /&gt;/*&amp;lt;![CDATA[*/&lt;br /&gt;.dp-highlighter  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    font-family: Monaco, Lucida Sans Typewriter, Bitstream Vera Sans Mono, monospace;&lt;br /&gt;    font-size: 12px;&lt;br /&gt;    margin: 18px 0 18px 0 !important;&lt;br /&gt;    overflow: auto;&lt;br /&gt;    padding-top: 1px;&lt;br /&gt;    width: 99%;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter ol,  .dp-highlighter ol li,  .dp-highlighter ol li span  {&lt;br /&gt;    border: none;&lt;br /&gt;    margin: 0;&lt;br /&gt;    padding: 0;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter a,  .dp-highlighter a:hover  {&lt;br /&gt;    background: none;&lt;br /&gt;    border: none;&lt;br /&gt;    margin: 0;&lt;br /&gt;    padding: 0;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .bar  {&lt;br /&gt;    padding-left: 45px;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.collapsed .bar,  .dp-highlighter.nogutter .bar  {&lt;br /&gt;    padding-left: 0px;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter ol  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;    list-style: decimal;&lt;br /&gt;    margin: 0px 0px 1px 45px !important;&lt;br /&gt;    padding: 0px;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.nogutter ol,  .dp-highlighter.nogutter ol li  {&lt;br /&gt;    list-style: none !important;&lt;br /&gt;    margin-left: 0px !important;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter ol li,  .dp-highlighter .columns div  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    border-left: 3px solid #3f3f3f;&lt;br /&gt;    color: #4c7073;&lt;br /&gt;    line-height: 14px;&lt;br /&gt;    list-style: decimal-leading-zero;&lt;br /&gt;    list-style-position: outside !important;&lt;br /&gt;    margin: 0 !important;&lt;br /&gt;    padding: 0 3px 0 10px !important;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.nogutter ol li,  .dp-highlighter.nogutter .columns div  {&lt;br /&gt;    border: 0;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .columns  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    color: gray;&lt;br /&gt;    overflow: hidden;&lt;br /&gt;    width: 100%;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .columns div  {&lt;br /&gt;    padding-bottom: 5px;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter ol li span  {&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.collapsed ol  {&lt;br /&gt;    margin: 0px;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.collapsed ol li  {&lt;br /&gt;    display: none;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.printing  {&lt;br /&gt;    border: none;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.printing .tools  {&lt;br /&gt;    display: none !important;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.printing li  {&lt;br /&gt;    display: list-item !important;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .tools  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    border-left: 3px solid #3f3f3f;&lt;br /&gt;    color: silver;&lt;br /&gt;    font: 9px Verdana, Geneva, Arial, Helvetica, sans-serif;&lt;br /&gt;    padding: 3px 8px 3px 10px;&lt;br /&gt;    padding-bottom: 10px;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.nogutter .tools  {&lt;br /&gt;    border-left: 0;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter.collapsed .tools  {&lt;br /&gt;    border-bottom: 0;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .tools a  {&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;    font-size: 9px;&lt;br /&gt;    margin-right: 10px;&lt;br /&gt;    text-decoration: none;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .tools a:hover  {&lt;br /&gt;    text-decoration: underline;&lt;br /&gt;}&lt;br /&gt;.dp-about  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;    margin: 0px;&lt;br /&gt;    padding: 0px;&lt;br /&gt;}&lt;br /&gt;.dp-about table  {&lt;br /&gt;    font-family: Tahoma, Verdana, Arial, sans-serif !important;&lt;br /&gt;    font-size: 11px;&lt;br /&gt;    height: 100%;&lt;br /&gt;    width: 100%;&lt;br /&gt;}&lt;br /&gt;.dp-about td  {&lt;br /&gt;    padding: 10px;&lt;br /&gt;    vertical-align: top;&lt;br /&gt;}&lt;br /&gt;.dp-about .copy  {&lt;br /&gt;    border-bottom: 1px solid #3f3f3f;&lt;br /&gt;    height: 95%;&lt;br /&gt;}&lt;br /&gt;.dp-about .title  {&lt;br /&gt;    color: #93e0e3;&lt;br /&gt;    font-weight: bold;&lt;br /&gt;}&lt;br /&gt;.dp-about .para  {&lt;br /&gt;    margin: 0 0 4px 0;&lt;br /&gt;}&lt;br /&gt;.dp-about .footer  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    border-top: 1px solid #3f3f3f;&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;    text-align: right;&lt;br /&gt;}&lt;br /&gt;.dp-about a  {&lt;br /&gt;    color: #93e0e3;&lt;br /&gt;}&lt;br /&gt;.dp-about .close  {&lt;br /&gt;    background-color: #3f3f3f;&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;    font-family: Tahoma, Verdana, Arial, sans-serif !important;&lt;br /&gt;    font-size: 11px;&lt;br /&gt;    height: 22px;&lt;br /&gt;    width: 60px;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .plain, .dp-xml .cdata, .dp-xml .attribute  {&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .comment, .dp-highlighter .comments  {&lt;br /&gt;    color: #7f9f7f;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .string, .dp-xml .attribute-value  {&lt;br /&gt;    color: #cc9393;&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .keyword, .dp-xml .tag, .dp-xml .tag-name  {&lt;br /&gt;    color: #f0dfaf;&lt;br /&gt;    font-weight: bold&lt;br /&gt;}&lt;br /&gt;.dp-highlighter .preprocessor {&lt;br /&gt;    color: #dcdccc;&lt;br /&gt;} &lt;br /&gt;/*]]&amp;gt;*/&lt;br /&gt;&amp;lt;/style&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-6952462609662949439?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/6952462609662949439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=6952462609662949439' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/6952462609662949439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/6952462609662949439'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/12/zenburn-blogger-template-with-syntax.html' title='Zenburn Blogger Template with Syntax Highlighting for Code Examples'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-106331306600587707</id><published>2008-12-22T16:32:00.016-06:00</published><updated>2009-01-14T10:41:47.932-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>A Threading Class for Javascript: Reworked</title><content type='html'>I was playing around with my &lt;a href="http://elijahr.blogspot.com/2008/12/threading-class-for-javascript.html"&gt;threading class for Javascript&lt;/a&gt;, and decided to rework it a little bit.  The little research I've done indicates that as of this writing, no browser's Javascript engine implements actual threading under the hood.  So, perhaps a better title for this post would be "An Asynchronous Execution Class for Javascript."  Basically, you pass an array of &lt;cmd&gt;Callback&lt;/cmd&gt; objects into the constructor for a &lt;cmd&gt;Thread&lt;/cmd&gt;.  When you call &lt;cmd&gt;Thread.start()&lt;/cmd&gt; the sequence of callbacks are executed synchronously, from a "driver" function that is queued to run after the current call stack terminates.  Not very robust, but I could see it coming in handy in some circumstances, especially involving page interactivity and event-handling.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;Array.prototype.add = function(object) {&lt;br /&gt;    // easy way to append to an array&lt;br /&gt;    this[this.length] = object;&lt;br /&gt;}&lt;br /&gt;Callback = function(fun, args) {&lt;br /&gt;    this.fun = function(){&lt;br /&gt;        fun(args)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;Thread = function (callbacks) {&lt;br /&gt;    /*  simulates thread-like functionality for javascript&lt;br /&gt;    Example:&lt;br /&gt;    callbacks = new Array();&lt;br /&gt;    // an array to hold callback functions&lt;br /&gt;    callbacks.add( new Callback(&lt;br /&gt;                        function(words) {&lt;br /&gt;                            alert(words[0]+words[1])&lt;br /&gt;                        }&lt;br /&gt;                        ,&lt;br /&gt;                        ["hello ","from callback 1"]));&lt;br /&gt;&lt;br /&gt;    callbacks.add( new Callback(&lt;br /&gt;                        function(words) {&lt;br /&gt;                            alert(words[0]+words[1])&lt;br /&gt;                        }&lt;br /&gt;                        ,&lt;br /&gt;                        ["hello ","from callback 2"]));&lt;br /&gt;&lt;br /&gt;    callbacks.add( new Callback(&lt;br /&gt;                        function(words) {&lt;br /&gt;                            alert(words[0]+words[1])&lt;br /&gt;                        }&lt;br /&gt;                        ,&lt;br /&gt;                        ["hello ","from callback 3"]));&lt;br /&gt;&lt;br /&gt;    callbacks.add( new Callback(&lt;br /&gt;                        function(words) {&lt;br /&gt;                            alert(words[0]+words[1])&lt;br /&gt;                        }&lt;br /&gt;                        ,&lt;br /&gt;                        ["hello ","from callback 4"]));&lt;br /&gt;&lt;br /&gt;    var myThread = new Thread(callbacks);&lt;br /&gt;    myThread.start();&lt;br /&gt;    */&lt;br /&gt;    this.start = function() {&lt;br /&gt;        var thread = function () {&lt;br /&gt;            for (var i=0;i&amp;lt;callbacks.length;i++) {&lt;br /&gt;                callbacks[i].fun();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        setTimeout(thread,0);&lt;br /&gt;        // initiates the asynchronous call and returns control back to original caller&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;Thread.sleep = function (delay){&lt;br /&gt;    /* simulates a Thread pause for 'delay' milliseconds&lt;br /&gt;         known issues:&lt;br /&gt;           while sleeping, browser is non-interactive&lt;br /&gt;           some browsers will warn the user that an infinite loop may be in progress&lt;br /&gt;    */&lt;br /&gt;    var startTime = new Date().getTime();&lt;br /&gt;    while (new Date().getTime() &amp;lt; startTime + delay){}&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-106331306600587707?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/106331306600587707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=106331306600587707' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/106331306600587707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/106331306600587707'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/12/threading-class-for-javascript-reworked.html' title='A Threading Class for Javascript: Reworked'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-4423435636228482947</id><published>2008-12-16T13:29:00.032-06:00</published><updated>2009-01-14T10:30:51.889-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>A Threading Class for Javascript</title><content type='html'>Note: please see &lt;a href="http://elijahr.blogspot.com/2008/12/threading-class-for-javascript-reworked.html#106331306600587707"&gt;this post&lt;/a&gt; for an updated version of this code.&lt;br /&gt;&lt;br /&gt;Most modern programming languages have a Threading class that allows the user to fork from a program's main thread and execute code asynchronously.  I have been using Javascript a lot lately, and although it doesn't provide a Threading class or even a &lt;cmd&gt;Thread.sleep()&lt;/cmd&gt; type of function, it turns out it is not so hard to throw something together using &lt;cmd&gt;setTimeout&lt;/cmd&gt; and &lt;cmd&gt;setInterval&lt;/cmd&gt; with anonymous functions.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;Thread = function (threadFunction,&lt;br /&gt;                   threadCompletedFunction,&lt;br /&gt;                   threadStartedFunction,&lt;br /&gt;                   threadProgressCallback,&lt;br /&gt;                   threadProgressCallbackTimeout) {&lt;br /&gt;    /*  creates a fork off of the main Javascript thread and allows that thread to have callbacks for different states.&lt;br /&gt;    Example usage:&lt;br /&gt;    var myThread = new Thread(  function(){alert('in the main function');},&lt;br /&gt;                                function(){alert('thread completed');},&lt;br /&gt;                                function(){alert('thread started ');},&lt;br /&gt;                                function(){alert('checking progress...');},&lt;br /&gt;                                500 ); // the progress checking function is looped every 500 ms&lt;br /&gt;    myThread.start();&lt;br /&gt;    */&lt;br /&gt;    &lt;br /&gt;    // private  variables&lt;br /&gt;    var threadProgressCallbackSwitch = true;&lt;br /&gt;    var progressCallbackId;&lt;br /&gt;    &lt;br /&gt;    // the progress callback is repeatedly called by setInterval&lt;br /&gt;    // so this wrapper is used to allow the loop to exit at some point via clearInterval&lt;br /&gt;    var threadProgressCallbackCaller = function() {&lt;br /&gt;        threadProgressCallbackSwitch ? threadProgressCallback() : clearInterval(progressCallbackId);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    // replace undefined parameters with empty functions&lt;br /&gt;    if (threadFunction == undefined) threadFunction = function(){}&lt;br /&gt;    if (threadCompletedFunction == undefined) threadCompletedFunction = function(){}&lt;br /&gt;    if (threadStartedFunction == undefined) threadStartedFunction = function(){}&lt;br /&gt;    &lt;br /&gt;    // define the main thread driver&lt;br /&gt;    this.start = function() {&lt;br /&gt;        var thread = function () {&lt;br /&gt;            if (threadProgressCallback != undefined) {&lt;br /&gt;                // if there is a progress checking callback, start looping it&lt;br /&gt;                if (threadProgressCallbackTimeout == undefined) threadProgressCallbackTimeout = 300;&lt;br /&gt;                progressCallbackId = setInterval(threadProgressCallbackCaller, threadProgressCallbackTimeout);&lt;br /&gt;            }&lt;br /&gt;            threadStartedFunction();&lt;br /&gt;            threadFunction();&lt;br /&gt;            threadCompletedFunction();&lt;br /&gt;            threadProgressCallbackSwitch = false;&lt;br /&gt;        }&lt;br /&gt;        setTimeout(thread,0); // initiates the asynchronous call and returns control back to original caller&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;Thread.sleep = function (delay){&lt;br /&gt;    /* simulates a Thread pause for 'delay' milliseconds&lt;br /&gt;         known issues:&lt;br /&gt;           while sleeping, browser is non-interactive&lt;br /&gt;           some browsers will warn the user that an infinite loop may be in progress&lt;br /&gt;    */&lt;br /&gt;    var startTime = new Date().getTime();&lt;br /&gt;    while (new Date().getTime() &amp;amp;lt; startTime + delay){}&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-4423435636228482947?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/4423435636228482947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=4423435636228482947' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4423435636228482947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4423435636228482947'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/12/threading-class-for-javascript.html' title='A Threading Class for Javascript'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-3160438200466710070</id><published>2008-10-29T14:57:00.010-05:00</published><updated>2009-01-14T10:31:16.324-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>IE6 peek-a-boo bug</title><content type='html'>&lt;del&gt;I was trying to manipulate the DOM to workaround the IE6 peekaboo bug, but none of the recommended methods seemed to work.  I thought up this neat trick:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;!-- elijahr peekaboo fix --&amp;gt;&lt;br /&gt;&amp;lt;img src="" alt="" style="display:none" onload="javascript:this.parentNode.innerHTML=this.parentNode.innerHTML+' ';"/&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;It basically just rebuilds the corrupted DOM section through javascript and forces IE 6 to render correctly.  You can put it only in the places you need it, or right under the &lt;cmd&gt;body&lt;/cmd&gt; tag.  Just make the &lt;cmd&gt;img&lt;/cmd&gt; element a child of whatever element is giving you issues.  A broader, but somewhat slower approach that might work would be to simply set the &lt;cmd&gt;onload&lt;/cmd&gt; event of the &lt;cmd&gt;body&lt;/cmd&gt; tag to:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;body onload="javascript:this.innerHTML=this.innerHTML+' ';"&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;But, that might not work in every case.  Peek-a-boo is a sneaky fiend of a bug.&lt;br /&gt;&lt;br /&gt;Cheers.&lt;/del&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-3160438200466710070?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/3160438200466710070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=3160438200466710070' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3160438200466710070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3160438200466710070'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/10/ie6-peek-boo-bug-elijahr-fix.html' title='IE6 peek-a-boo bug'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-3640881156438422370</id><published>2008-10-02T16:01:00.010-05:00</published><updated>2009-01-14T10:32:13.451-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>unpacking tarballs efficiently onto flash devices</title><content type='html'>I recently installed NetBSD/hpcmips onto an old Windows CE based handheld PC.  I tried installing pkgsrc, NetBSD's package management system, but the tarball was nowhere near done extracting to the CompactFlash card, even after leaving &lt;cmd&gt;tar -xzf&lt;/cmd&gt; running all night.  This is expected, given the incredibly low specs of the handheld PC, but I wanted to do something faster.&lt;br /&gt;&lt;br /&gt;I fired up a blank virtual machine in VMWare Server, allocating a single gigabyte of disk space and a half gigabyte of RAM.  I also added a USB controller to access my CF disk with later.  I booted the machine from a NetBSD installation ISO image, and proceeded with a minimal installationg of NetBSD/i386.  NetBSD is incredibly optmized and minimalist, so this took less than 5 minutes.  I then rebooted the VM, and ran these commands:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mount /dev/sd-my-cf-card's-netbsd-partition /mnt/&lt;br /&gt;tar -xzf pkgsrc.tar.gz -b 52000 -C /mnt/usr/&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;This finished a lot more quickly.  The &lt;cmd&gt;-b&lt;/cmd&gt; parameter sets the block size.  I set this to approximately 26MB, which is the size of the pkgsrc tarball, meaning that the tarball was unpacked completely to RAM before being written to disk.  This is a lot faster than:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mount /dev/sd-my-cf-card's-netbsd-partition /mnt/&lt;br /&gt;tar -xzf pkgsrc.tar.gz -C /mnt/usr/&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Try it and see!  If working with &lt;cmd&gt;dd&lt;/cmd&gt;, use the &lt;cmd&gt;bs&lt;/cmd&gt; parameter to set the block size and see that you will get things done a lot faster as well.   You'll have to play around with numbers; obviously you don't want to make the block size any bigger than your available RAM or your operating system will start swapping to disk anyway.  My general rule of thumb is to use half of my available RAM as the blocksize, which should usually provide maximum efficiency and speed.  Cheers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-3640881156438422370?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/3640881156438422370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=3640881156438422370' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3640881156438422370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3640881156438422370'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/10/unpacking-tarballs-efficiently-onto.html' title='unpacking tarballs efficiently onto flash devices'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-1864657777612872160</id><published>2008-08-22T12:22:00.013-05:00</published><updated>2009-01-14T10:32:32.972-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Installing Debian Etch-and-a-half onto a Powerbook G3 (Wallstreet)</title><content type='html'>This is the hardware and software I used, since my bay CD Drive was broken.  As you can see, I have a lot of handy junk laying around.  It helps to live 3 blocks from Micro Center as well.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1x PCMCIA-&gt;USB adapter&lt;/li&gt;&lt;li&gt;1x 2GB USB Flash Drive&lt;/li&gt;&lt;li&gt;1x IDE CD/DVD-RW Drive&lt;/li&gt;&lt;li&gt;1x USB -&gt; IDE hard drive enclosure, opened up (to connect the CD Drive)&lt;/li&gt;&lt;li&gt;BootX 1.2.2&lt;/li&gt;&lt;li&gt;CarbonLib_1.0.4.smi.bin&lt;/li&gt;&lt;li&gt;aladdin-expander-6.0.sea.hqx&lt;/li&gt;&lt;li&gt;Mac OS 8.1, installed to Mac's HD&lt;/li&gt;&lt;li&gt;debian-40r4a-powerpc-netinst.iso, burned to CD&lt;/li&gt;&lt;li&gt;Ethernet connection to internet&lt;/li&gt;&lt;li&gt;method to transfer files to and from the powerbook (I used a FAT32 formatted CF card in a PCMCIA adapter)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The first step is to get the bootloader installed.  I used the BootX bootloader, but for some reason the downloaded .sit files wouldn't expand, except for v1.1.3.  I had Stuffit Expander 5, so decided to find an upgrade.  I googled around for aladdin-expander-6.0.sea.hqx and got what I needed.  However, this required me to download CarbonLib.  After that, the .sit files expanded with no problem.  The latest BootX at the time of this writing was BootX v.1.2.2.&lt;br /&gt;&lt;br /&gt;I placed the BootX App into Control Panels, and the BootX Extension into Extensions.&lt;br /&gt;I tranferred a copy of the /boot/initrd and /boot/vmlinux files from the Etch CD to my Powerbook.  I placed initrd.gz and vmlinux in /System Folder/Linux Kernels on my PowerBook.  Then I unplugged my PCMCIA cards, rebooted and was presented with the BootX bootloader window.  I hit tab to select linux, then I went into Options, and turned SCSI on, and set the ram disk to initrd.gz.  I saved the preferences, plugged in both the USB Flash drive and the USB CD Drive  to the PCMCIA adapter and booted linux.&lt;br /&gt;&lt;br /&gt;I was presented with the Debian installer.  Video was a little strange, but I figured I could deal with that later.  I had to manually set the CD-ROM device to /dev/sr0 (check the debug console with ALT+F4 for info on your devices if your CD drive isn't autodetected).  The ethernet drivers loaded and DHCP assigned an IP, then I partitioned my USB Flash drive (/dev/sda, NOT /dev/hda -&gt; that's MacOS and we need it to boot with BootX).  Installation of the core packages took a while with my meager 64MB of RAM.&lt;br /&gt;&lt;br /&gt;When installation completed, I opted not to install a bootloader, as I saw reports of issues with quik and the Wallstreet.  Instead, I pressed ALT+F4 to open a terminal, and copied /boot/vmlinux and /boot/initrd.img to my web server using netcat.  I pressed ALT+F1 to get back to the installer, and let it reboot.  I booted into MacOS, and downloaded the ramdisk image and kernel to my Linux Kernels folder, reconfigured BootX for the new kernel, initrd, and root device (/dev/sda), saved the preferences, and rebooted.. voila!  A customizable debian has revived this computer.  Well, not quite.  My PCMCIA-&gt; USB adapter wasn't being registered when the kernel loaded modules from the initial ram disk.  So, on my main Linux desktop, I did this, using the initrd.img from the powerbook's copy of Debian.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mkdir /tmp/initrd_ppc/&lt;br /&gt;cd /tmp/initrd_ppc&lt;br /&gt;gunzip &lt; /path/to/ppc/initrd.img | cpio -i --make-directories &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then I plugged in the Flash drive with the Powerbook's Debian on it:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mount /dev/sdb2 /mnt&lt;br /&gt;cp -R /mnt/lib/modules/2.6.18-6-powerpc/kernel/drivers/pcmcia /tmp/initrd_ppc/lib/modules/2.6.18-6-powerpc/kernel/drivers/&lt;br /&gt;cp -R /mnt/lib/modules/2.6.18-6-powerpc/kernel/drivers/usb /tmp/initrd_ppc/lib/modules/2.6.18-6-powerpc/kernel/drivers/&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I didn't know what modules I would specifically need, so I just lazily added everything from PCMCIA and added USB core:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;echo "rsrc_nonstatic" &gt;&gt; conf/modules&lt;br /&gt;echo "pcmcia_core" &gt;&gt; conf/modules&lt;br /&gt;echo "pcmcia" &gt;&gt; conf/modules&lt;br /&gt;echo "yenta_socket" &gt;&gt; conf/modules&lt;br /&gt;echo "usb_core" &gt;&gt; conf/modules&lt;br /&gt;echo "i82092" &gt;&gt; conf/modules&lt;br /&gt;echo "pd6729" &gt;&gt; conf/modules&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then all I had to do was pack the initrd up again:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;find /tmp/initrd_ppc/ | cpio -H newc -o &gt; initrd.cpio&lt;br /&gt;gzip initrd.cpio&lt;br /&gt;mv initrd.cpio.gz initrd-custom.img&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Copy initrd-custom.img to the Powerbook's Mac OS partition, have BootX point to it, and you should be able to reboot into Linux.  Make sure you pass 'root=/dev/sda2' as kernel arguments (or /dev/whereveryourdebianpartitionis).&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;Elijahr&lt;br /&gt;&lt;br /&gt;PS - I later upgraded to Lenny (current Debian testing) and it went quite well. All i had to do was the standard modification of /etc/apt/sources.list and then a dist-upgrade.  Then I just modifed the initrd again. I'm in the process of repurposing the laptop as a videophone and cookie dispenser for my sweet old pit bull mutt while I am at work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;References:&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.linuxforums.org/forum/linux-kernel/82174-extracting-initrd-image.html"&gt;http://www.linuxforums.org/forum/linux-kernel/82174-extracting-initrd-image.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.davison.org.nz/projects/hardware-software/debian-3-1-sarge-on-g3-powerbook-wallstreet"&gt;http://www.davison.org.nz/projects/hardware-software/debian-3-1-sarge-on-g3-powerbook-wallstreet&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-1864657777612872160?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/1864657777612872160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=1864657777612872160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/1864657777612872160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/1864657777612872160'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/08/installing-debian-etch-and-half-onto.html' title='Installing Debian Etch-and-a-half onto a Powerbook G3 (Wallstreet)'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-3642469403747015267</id><published>2008-08-11T13:01:00.009-05:00</published><updated>2009-01-14T10:32:45.110-06:00</updated><title type='text'>Preventing DynDNS.org update abuse</title><content type='html'>I have been using the free service at www.dyndns.org to keep tabs on my home server's IP address.  However, I replaced my wireless/ethernet router, and the new one did not have built in dyndns.org updating, as my old one did.&lt;br /&gt;&lt;br /&gt;I decided to use a software solution on my Debian based server.  At first, I tried ddclient, but for some reason, it would stop sending updates after a few hours.  Then I tried inadyn, but that caused my hostnames to get flagged for abuse.  It seemed that neither of the tools was correctly checking the IP address before attempting to make the update, they were just sending the updates periodically even when my IP hadn't changed.  This violates dyndns.org's abuse policy, so I just decided to write a simple wrapper script.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;#!/bin/bash&lt;br /&gt;DYNIP=`host foo.example.com`&lt;br /&gt;DYNIP=${DYNIP#* has address }&lt;br /&gt;&lt;br /&gt;wget -O- http://www.whatismyip.org/ 2&gt;/dev/null    &gt; /tmp/currentip&lt;br /&gt;&lt;br /&gt;echo current ip\: `cat /tmp/currentip`&lt;br /&gt;echo ip on file\: $DYNIP&lt;br /&gt;&lt;br /&gt;if [[ \"`cat /tmp/currentip`\" = *\"$DYNIP\"* ]]; then&lt;br /&gt;    echo "ip is up to date"&lt;br /&gt;else&lt;br /&gt;    echo "must update"&lt;br /&gt;    /usr/sbin/inadyn&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;rm /tmp/currentip&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;then i set up inadyn as follows:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# /etc/inadyn.conf&lt;br /&gt;&lt;br /&gt;--username myuser --password mypass --alias foo.example.com --iterations 1&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So now I just have my script running as a cron job once every hour.  From my understanding, I shouldn't need this wrapper, but both inadyn and ddclient were mysterously updating my hostname mapping when they shouldn't have.  I could very well have configured them wrong, but things looked ok to me and this solution works, so I'll let it be.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-3642469403747015267?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/3642469403747015267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=3642469403747015267' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3642469403747015267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3642469403747015267'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/08/preventing-dyndnsorg-update-abuse.html' title='Preventing DynDNS.org update abuse'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-7837245694226749562</id><published>2008-05-06T15:31:00.010-05:00</published><updated>2009-01-14T10:33:13.938-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gnu/linux'/><title type='text'>Damn Small Linux on a USB-ZIP for Via C3 / Epia Motherboard</title><content type='html'>The VIA C3 is an x86 compatible chip used in a a bunch of popular and cheap motherboards.  It isn't fully instruction-set compatible with the newer intel chips, though, so a lot of the minor and mundane optimizations people use with their compiler will produce binaries that crash when run on the VIA C3.  So, I had trouble finding a linux distribution that would actually run.  Debian seemed to work, but a lot of the packages in the apt repositories did not.&lt;br /&gt;Eventually, I just wanted to make a little network appliance with the board, but I had trouble getting it to boot from any distributions I installed to a USB flash drive.  It turns out that there are some issues booting these motherboards with USB-HDD media.  USB-ZIP mode was said to work, though, which basically puts everything on partition 4 and does some strange stuff with the cylinder information.  Sounds ok.&lt;br /&gt;&lt;br /&gt;I decided to go with Damn Small Linux (4.2.5 in my case) with syslinux as the boot loader, using a FAT filesystem, of course.&lt;br /&gt;&lt;br /&gt;So, first thing was to correctly format my Flash drive. From the syslinux/usbboot documentation:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;The script "mkdiskimage" which is supplied with the syslinux&lt;br /&gt;distribution can be used to initialize USB keys in a Zip-like fashion.&lt;br /&gt;To do that, calculate the correct number of cylinders (31 in the&lt;br /&gt;example above), and, if your USB key is /dev/sda (CHECK THE KERNEL&lt;br /&gt;MESSAGES CAREFULLY - IF YOU ENTER THE WRONG DISK DRIVE IT CANNOT BE&lt;br /&gt;RECOVERED), run:&lt;br /&gt;&lt;br /&gt;       &lt;code&gt;mkdiskimage -4 /dev/sd[X] 0 64 32&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;(The 0 means automatically determine the size of the device, and -4&lt;br /&gt;means mimic a zipdisk by using partition 4.)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;After that finished up, I ran:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;syslinux /dev/sdb4&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;to install the bootloader.  then it was a simple matter of getting the latest dsl-embedded.zip from one of damn small linux's mirrors, and unzipping its contents onto the mounted /dev/sdb4 partition.  unmount, stick the USB-ZIP drive i just made into the Via computer, and bang. damn small linux.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-7837245694226749562?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/7837245694226749562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=7837245694226749562' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/7837245694226749562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/7837245694226749562'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/05/damn-small-linux-on-usb-zip-for-via-c3.html' title='Damn Small Linux on a USB-ZIP for Via C3 / Epia Motherboard'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-2080156149720354030</id><published>2008-04-28T18:29:00.006-05:00</published><updated>2009-01-14T10:34:19.249-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><title type='text'>Samsung SGH-T509, T-Mobile GPRS, Bluetooth DUN on a Debian GNU/Linux Laptop</title><content type='html'>&lt;span style="font-weight: bold;"&gt;My Setup:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Asus EeePC with Debian GNU/Linux Lenny/Sid, custom real-time patched 2.6.23 kernel&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Bluetooth enabled T-Mobile Samsung SGH-T509&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Zoom USB bluetooth adapter&lt;/li&gt;&lt;li&gt;GPRS Internet (T-MobileWeb aka T-zones)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;installed packages: bluetooth ppp gnome-ppp&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Technically speaking, any Bluetooth phone with DUN support should work, but the breadth of hackery here is in the details.  For instance, with my phone, doing a scan with 'hcitool scan' produced no results for my t509, although it should have.  Once I successfully paired my phone and laptop, I found my DUN channel mostly through guesswork (its on channel 1). The only reliable way I was able to get my phone to dial was by using a &lt;a href="http://howtoforge.com/connecting-gprs-from-ubuntu-gutsy"&gt;patched version of gnome-ppp for ubuntu&lt;/a&gt;, run as the root user.&lt;br /&gt;&lt;br /&gt;Googling around turned up &lt;a href="http://www.newt.com/debian/treo650.html"&gt;Using the Palm Treo 650 with Debian GNU/Linux&lt;/a&gt; and &lt;a href="http://timhatch.com/projects/t509-osx/"&gt;&lt;span style="text-decoration: underline;"&gt;Modem Script for Samsung t509&lt;/span&gt;&lt;/a&gt;.  Looking through scripts on those pages, I was able to piece together the initialization strings I needed to open a GPRS connection.&lt;br /&gt;&lt;br /&gt;My /root/.wvdial.conf is as follows:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;[Dialer Defaults]&lt;br /&gt;Modem = /dev/rfcomm0&lt;br /&gt;ISDN = off&lt;br /&gt;Modem Type = USB Modem&lt;br /&gt;Baud = 115200&lt;br /&gt;Init = ATX3&lt;br /&gt;Init2 = AT&lt;br /&gt;Init3 = ATQ0 V1 E1 S0=0 &amp;amp;C1 &amp;amp;D2 +FCLASS=0&lt;br /&gt;Init4 = AT&amp;amp;K3&lt;br /&gt;Init5 = AT+CGDCONT=1,"IP","WAP.VOICESTREAM.COM"&lt;br /&gt;Init6 =&lt;br /&gt;Init7 =&lt;br /&gt;Init8 =&lt;br /&gt;Init9 =&lt;br /&gt;Phone = *99***1#&lt;br /&gt;Phone1 =&lt;br /&gt;Phone2 =&lt;br /&gt;Phone3 =&lt;br /&gt;Phone4 =&lt;br /&gt;Dial Prefix =&lt;br /&gt;Dial Attempts = 1&lt;br /&gt;Dial Command = ATM1L3DT&lt;br /&gt;Ask Password = off&lt;br /&gt;Password = guest&lt;br /&gt;Username = guest&lt;br /&gt;Auto Reconnect = off&lt;br /&gt;Abort on Busy = off&lt;br /&gt;Carrier Check = off&lt;br /&gt;Check Def Route = off&lt;br /&gt;Abort on No Dialtone = off&lt;br /&gt;Stupid Mode = on&lt;br /&gt;Idle Seconds = 0&lt;br /&gt;Auto DNS = on&lt;br /&gt;;Minimize = off&lt;br /&gt;;Dock = on&lt;br /&gt;;Do NOT edit this file by hand!&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;To connect just create a menu entry for 'gksudo gnome-ppp' and you should be all set.  You will need to use a web proxy to surf the web, and most ports are blocked.  Still, it is useful to have internet wherever you have cell phone coverage.  T-Mobile has a proxy you can use, google around.  If you don't have a /dev/rfcomm0, this may help: http://pratyeka.org/rfcomm/&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;References:&lt;br /&gt;&lt;br /&gt;http://howtoforge.com/connecting-gprs-from-ubuntu-gutsy&lt;br /&gt;http://easyconnect.linuxuser.hu/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-2080156149720354030?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/2080156149720354030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=2080156149720354030' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/2080156149720354030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/2080156149720354030'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/04/samsung-sgh-t509-t-mobile-gprs_28.html' title='Samsung SGH-T509, T-Mobile GPRS, Bluetooth DUN on a Debian GNU/Linux Laptop'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-392633179868839808</id><published>2008-04-20T00:04:00.003-05:00</published><updated>2009-01-14T10:33:57.791-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>Netcat, the network swiss army knife</title><content type='html'>&lt;p&gt;&lt;strong&gt;What is netcat?&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;From the&lt;a href="http://netcat.sourceforge.net/"&gt; official GNU page&lt;/a&gt;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;Netcat is a featured networking utility which reads and writes data across network connections, using the TCP/IP protocol.&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Have you ever been in a bind, where you need to transfer a file between two networked computers, but neither of them has any file transfer services running?  You could install and configure SMB, NFS, or FTP, but if you just need to transfer a few files occasionally, or you are working with very limited system resources, perhaps it is best to just use netcat.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;However, netcat is not just a file transfer utility.  It&amp;#8217;s beauty lies in it&amp;#8217;s simplicity; you can use netcat to pipe data across a network, in the exact same way that you can pipe data on a Unix or Windows shell.  This makes it extremely simple for novice scripters to transfer any kind of data over the network, even continuous streams of data.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Here&amp;#8217;s how to send a file to hostname or IP address &amp;#8216;foo&amp;#8217;, for some port number &amp;#8216;bar&amp;#8217;.&lt;br /&gt;&lt;br /&gt;On &amp;#8216;foo&amp;#8217;, run this command:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;nc -lp bar &amp;gt; /path/to/save/file/to &lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Then on the file sender:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;cat /path/to/original/file | nc foo bar&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;So, what else can you do with netcat?  Here&amp;#8217;s a fun example: on some machine with a microphone connected, and mixer levels set accordingly:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;cat /dev/dsp | netcat -d -h foo -p bar&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;And then on some other machine, &amp;#8216;foo&amp;#8217;, with the firewall configured to allow TCP connections to port &amp;#8216;bar&amp;#8217;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;netcat -lp bar &amp;gt; /dev/dsp&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;What does this do?&lt;br /&gt;&lt;br /&gt;It streams your microphone input to the speakers of &amp;#8216;foo&amp;#8217;.  At least, it should in theory.  I don&amp;#8217;t have a way to test it right now, but let me know if it works for you.  It may require slight modification.  Careful that the speakers and microphone aren&amp;#8217;t in the same room, or you&amp;#8217;ll get feedback!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Here&amp;#8217;s another fun example: a very tiny webserver (modified example from &lt;a href="http://www.stearns.org/doc/nc-intro.current.html"&gt;http://www.stearns.org/doc/nc-intro.current.html&lt;/a&gt;).&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;printf "Content-Type: text/html\n\n" &amp;gt; ~/mywebpage.html&lt;br /&gt;&lt;br /&gt;echo 'hello world' &amp;gt;&amp;gt; ~/mywebpage.html&lt;br /&gt;&lt;br /&gt;while true ; do cat ~/mywebpage.html | nc -l -p 80 | head –bytes 2000 &amp;gt;&amp;gt; /tmp/requests ; date&amp;gt;&amp;gt; /tmp/requests ; done&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Of course, I can&amp;#8217;t test that right now either&amp;#8230;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Well, hope you had fun, and I hope it worked.  Let me know if you found any modifications that were necessary to get things to work right. Cheers.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-392633179868839808?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/392633179868839808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=392633179868839808' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/392633179868839808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/392633179868839808'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/04/what-is-netcat-from-official-gnu-page.html' title='Netcat, the network swiss army knife'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-4625372579460818174</id><published>2008-04-16T02:10:00.008-05:00</published><updated>2008-04-16T02:30:09.064-05:00</updated><title type='text'>synthesizer programming pipe dreams</title><content type='html'>I have a Nord Modular synthesizer, by Clavia.  It is really a fantastic synthesizer; 4 DSPs and there is a nice GUI to create your synth patches with.&lt;br /&gt;&lt;br /&gt;There are a plethora of software programs that do the same thing, such as SynthEdit, OpenSoundWorld, MaxMSP, and PureData.  I've used them all, and I constantly find myself wishing that there was a more powerful sequencer module built-in to all of these synthesizers.  I don't like using multiple programs to make music (sequencer/tracker, audio recording, synthesizer, etc), because I find all the switching modes to be distracting.  I like the MSP and PD approach of building it all from scratch and keeping it all together, but the interface is very important to me, and the one thing I don't like to mix are the controls in the same place as the "code behind".&lt;br /&gt;&lt;br /&gt;So, early in my computer science career, I decided to write my own modular synthesizer, with a heavy emphasis on the sequencer. First, I played around with C++, then I learned Java, and I tried that, but neither of those languages really seemed very nice for creating a modular synthesizer.  I really loved the Scheme programming language, and thought that its functional style and emphasis on tail-recursion would be ideal for DSP and modularity.  However, I didn't want to have to build my own MIDI and audio libraries from scratch, and I wasn't a good enough programmer to figure out how to write a foreign-function-interface (once I started mixing C pointers in with Scheme, I just got confused).  So, along comes Python.  Python has extensive libraries, many related to MIDI, audio, and music, and it has a nice, elegant style somewhat reminiscent of Scheme.  I am looking into PySndObj and Csound right now.  I'll update here as things progress, if they do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-4625372579460818174?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/4625372579460818174/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=4625372579460818174' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4625372579460818174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/4625372579460818174'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/04/synthesizer-programming-pipe-dreams.html' title='synthesizer programming pipe dreams'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-7470584129855252334</id><published>2008-04-08T20:50:00.006-05:00</published><updated>2009-01-14T10:34:49.120-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>unix one-liners: sorted filesystem usage</title><content type='html'>i have a total storage capacity of 6gb in my laptop, so its often necessary to do a little housecleaning.  the best way I've found to do this, so far, is to get a list of the directories with the highest disk usage, and sort it for easy viewing.  from there, I might see some stray files I don't need anymore that I can dispose.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sudo du -c / | sort -g &gt; sorted&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;"sudo du -c /" will recursively get directory disk usage for the entire filesystem.  I pipe that into "sort -g" which does a generic numeric sort, and then I pipe that into a file called "sorted" which I can then look through at my convenience.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-7470584129855252334?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/7470584129855252334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=7470584129855252334' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/7470584129855252334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/7470584129855252334'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/04/unix-one-liners-sorted-filesystem-usage.html' title='unix one-liners: sorted filesystem usage'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-8181401929796688980</id><published>2008-04-01T08:30:00.014-05:00</published><updated>2009-01-14T10:35:03.573-06:00</updated><title type='text'>april fools prank:  'when doves cry' on all the office printers' display panels</title><content type='html'>&lt;blockquote&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;doves=( "Dig if u will the picture" "Of u and I engaged in a kiss" "The sweat of your body covers me" "Can u my darling" "Can u picture this?" "Dream if u can a courtyard" "An ocean of violets in bloom" "Animals strike curious poses" "They feel the heat" "The heat between me and u" "How can u just leave me standing?" "Alone in a world thats so cold? (so cold)" "Maybe Im just 2 demanding" "Maybe Im just like my father 2 bold" "Maybe youre just like my mother" "Shes never satisfied (shes never satisfied)" "Why do we scream at each other" "This is what it sounds like" "When doves cry" "Touch if u will my stomach" "Feel how it trembles inside" "Youve got the butterflies all tied up" "Dont make me chase u" "Even doves have pride" "How can u just leave me standing?" "Alone in a world so cold? (world so cold)" "Maybe Im just 2 demanding" "Maybe Im just like my father 2 bold" "Maybe youre just like my mother" "Shes never satisfied (shes never satisfied)" "Why do we scream at each other" "This is what it sounds like" "When doves cry" "How can u just leave me standing?" "Alone in a world thats so cold? (a world thats so cold)" "Maybe Im just 2 demanding (maybe  maybe Im like my father)" "Maybe Im just like my father 2 bold (ya know hes 2 bold)" "Maybe youre just like my mother (maybe youre just like my mother)" "Shes never satisfied (shes never  never satisfied)" "Why do we scream at each other (why do we scream  why)" "This is what it sounds like" "When doves cry" "When doves cry (doves cry  doves cry)" "When doves cry (doves cry  doves cry)" "Dont cry (dont cry)" "When doves cry" "When doves cry" "When doves cry" "When doves cry (doves cry  doves cry  doves cry" "Dont cry" "Darling dont cry" "Dont cry" "Dont cry" "Dont dont cry")&lt;br /&gt;&lt;br /&gt;#55 for doves&lt;br /&gt;while [ 1 ]; do&lt;br /&gt;  for (i=0;i&lt;55;i+=1) {&lt;br /&gt;    ./hpsetdisp.pl 10.9.100.1 \"${doves[i]}\"&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;This will output the contents of the 'doves' array to the LCD panel on an HP printers in my office.  Just swap out the IP address for the IP of some HP printer in your office, and run the script.  You can do it from &lt;a href="http://www.cygwin.com/"&gt;cygwin for windows&lt;/a&gt; if you don't have any unix boxen.  There was a problem with some of the printers, they would error out after a few minutes, I think the memory was filling up too fast maybe?  Who knows.  It was fun while it lasted.  Maybe I'll work that out for next April.&lt;br /&gt;&lt;br /&gt;Of course unix or not, you'll still need bash, perl, and the script at &lt;a href="http://kovaya.com/perl/show.cgi?program=hpsetdisp.pl"&gt;http://kovaya.com/perl/show.cgi?program=hpsetdisp.pl&lt;/a&gt;&lt;br /&gt;put the perl script in the same directory as the bash script.&lt;br /&gt;&lt;br /&gt;My thanks to the writer of hpsetdisp.pl.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-8181401929796688980?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/8181401929796688980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=8181401929796688980' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/8181401929796688980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/8181401929796688980'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/04/april-fools-prank-when-doves-cry-on.html' title='april fools prank:  &apos;when doves cry&apos; on all the office printers&apos; display panels'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2266387177743068088.post-3143828861566489002</id><published>2008-03-15T13:38:00.009-05:00</published><updated>2009-01-14T10:35:27.686-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='eee'/><title type='text'>debian-eeepc suspend issues with networkmanager</title><content type='html'>I was having issues with NetworkManager being unable to talk to my wireless card after resuming my Eee running Debian (sid) with Xfce4.&lt;br /&gt;&lt;br /&gt;I was using the eeepc-acpi-scripts from the main debian repository, and not using the 'zzz' or 'wifi' scripts that some people recommend download, as they caused video issues on resume.&lt;br /&gt;&lt;br /&gt;So I made changes to the file at &lt;code&gt;/etc/acpi/actions/suspend.sh&lt;/code&gt;.  You'll find my modified suspend.sh below:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;#!/bin/sh&lt;br /&gt;# do nothing if package is removed&lt;br /&gt;[ -d /usr/share/doc/eeepc-acpi-scripts ] || exit 0&lt;br /&gt;if (runlevel | grep -q [06]) || (pidof '/sbin/shutdown' &gt; /dev/null); then&lt;br /&gt;exit 0&lt;br /&gt;fi&lt;br /&gt;brn_control=/proc/acpi/asus/brn&lt;br /&gt;brightness=$(cat $brn_control)&lt;br /&gt;#turn off wireless, stop network-manager&lt;/code&gt;&lt;code&gt;&lt;br /&gt;/etc/acpi/actions/wireless.sh off&lt;/code&gt;&lt;br /&gt;&lt;code&gt;/etc/init.d/dbus stop&lt;br /&gt;#suspend&lt;br /&gt;pm-suspend --quirk-s3-bios --quirk-dpms-on&lt;br /&gt;#picks up here for resume&lt;br /&gt;echo $brightness &gt; $brn_control&lt;br /&gt;#restart dbus (and thus nm), turn wireless back on&lt;br /&gt;/etc/init.d/dbus start&lt;br /&gt;/etc/acpi/actions/wireless.sh on&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;you may want to modify wireless.sh to retry turning wireless on until it is successful... i've found sometimes it quits, and it seems unnecessary for it to give up so soon.  maybe i'll post those changes later... just ask if you need them.&lt;br /&gt;related links:&lt;br /&gt;&lt;a href="http://fedoraproject.org/wiki/EeePc#head-6d7acf3097e76d25a5483d4ee3e918a990214053"&gt;http://fedoraproject.org/wiki/EeePc#head-6d7acf3097e76d25a5483d4ee3e918a990214053&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.andrewkilpatrick.org/mind/eee_pc/installation_notes.html"&gt;http://www.andrewkilpatrick.org/mind/eee_pc/installation_notes.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.debian.org/DebianEeePC/HowTo/Install#head-384237e454261661a1a9018df19f581a810e273f"&gt;http://wiki.debian.org/DebianEeePC/HowTo/Install#head-384237e454261661a1a9018df19f581a810e273f&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2266387177743068088-3143828861566489002?l=elijahr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elijahr.blogspot.com/feeds/3143828861566489002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2266387177743068088&amp;postID=3143828861566489002' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3143828861566489002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2266387177743068088/posts/default/3143828861566489002'/><link rel='alternate' type='text/html' href='http://elijahr.blogspot.com/2008/03/debian-eeepc-suspend-issues-with.html' title='debian-eeepc suspend issues with networkmanager'/><author><name>elijahr</name><uri>http://www.blogger.com/profile/09355750750097047432</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_cEb20uw8Nec/SWKQc-8OlMI/AAAAAAAAACY/yAfPIxVVdOg/S220/n822005781_901629_7868.jpg'/></author><thr:total>1</thr:total></entry></feed>
