[
  {
    "path": "README.md",
    "content": "# Bloody jQuery Plugins \n\nA small collection of useful functionality available by default in Dojo, though useful in plain-ole-JavaScript context.\n\n## hitch.js\n\nAdvanced scope manipulation in jQuery. For jQuery 1.3 and before, as 1.4 the official \"way\" to accomplish this is via $.proxy ... New versions of this module _may_ curry arguments, giving it an advantage over proxy. The Dojo version currently curries arguments.\n\n## pubsub.js\n\nAmbiguous communication plugin. Small API surface. Publish some message to listeners.\n\n## date.js\n\nDate functionality for jQuery, living in the $.date namespace. Provides date.add, date.compare, date.difference, and a few other small utility functions. Ignore the word `dojo` in the source. By way of JavaScript _magic_ it is actually a _jQuery_ plugin. I promise.\n\n## format.js\n\nPort of some random MIT/GPL Number formatting plugin to allow \"plain ole' Number formatting\" without requirement of the number being formatted be in the DOM. Retains API of original plugin, though exposes the formatter and parser publicly.\n\n# License\n\nBeing stolen directly from the Dojo Toolkit source, these plugins are released under a dual AFL/BSD license identical to Dojo proper. See http://dojotoolkit.org/license for more information.\n"
  },
  {
    "path": "Stateful.js",
    "content": "(function($){\n\n\t$.Stateful = function(args){\n\t\t$.extend(this, args);\n\t}\n\t\n\t$.extend($.Stateful.prototype, {\n\n\t\tget: function(/*String*/name){\n\t\t\t// summary:\n\t\t\t//\t\tGet a property on a Stateful instance.\n\t\t\t//\tname:\n\t\t\t//\t\tThe property to get.\n\t\t\t// description:\n\t\t\t//\t\tGet a named property on a Stateful object. The property may\n\t\t\t//\t\tpotentially be retrieved via a getter method in subclasses. In the base class\n\t\t\t//\t\tthis just retrieves the object's property. \n\t\t\t//\t\tFor example:\n\t\t\t//\t|\tstateful = new dojo.Stateful({foo: 3});\n\t\t\t//\t|\tstateful.get(\"foo\") // returns 3\n\t\t\t//\t|\tstateful.foo // returns 3\n\t\t\n\t\t\treturn this[name];\n\t\t},\n\n\t\tset: function(/*String*/name, /*Object*/value){\n\t\t\t// summary:\n\t\t\t//\t\tSet a property on a Stateful instance\n\t\t\t//\tname:\n\t\t\t//\t\tThe property to set. \n\t\t\t//\tvalue:\n\t\t\t//\t\tThe value to set in the property.\n\t\t\t// description:\n\t\t\t//\t\tSets named properties on a stateful object and notifies any watchers of \n\t\t\t//\t\tthe property. A programmatic setter may be defined in subclasses.\n\t\t\t//\t\tFor example:\n\t\t\t//\t|\tstateful = new dojo.Stateful();\n\t\t\t//\t|\tstateful.watch(function(name, oldValue, value){\n\t\t\t//\t|\t\t// this will be called on the set below\n\t\t\t//\t|\t}\n\t\t\t//\t|\tstateful.set(foo, 5);\n\t\t\t//\n\t\t\t//\tset() may also be called with a hash of name/value pairs, ex:\n\t\t\t//\t|\tmyObj.set({\n\t\t\t//\t|\t\tfoo: \"Howdy\",\n\t\t\t//\t|\t\tbar: 3\n\t\t\t//\t|\t})\n\t\t\t//\tThis is equivalent to calling set(foo, \"Howdy\") and set(bar, 3)\n\t\t\tif(typeof name === \"object\"){\n\t\t\t\tfor(var x in name){\n\t\t\t\t\tthis.set(x, name[x]); \n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tvar oldValue = this[name];\n\t\t\tthis[name] = value;\n\t\t\tif(this._watchCallbacks){\n\t\t\t\tthis._watchCallbacks(name, oldValue, value);\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\n\t\twatch: function(/*String?*/name, /*Function*/callback){\n\t\t\t// summary:\n\t\t\t//\t\tWatches a property for changes\n\t\t\t//\tname:\n\t\t\t//\t\tIndicates the property to watch. This is optional (the callback may be the \n\t\t\t//\t\tonly parameter), and if omitted, all the properties will be watched\n\t\t\t// returns:\n\t\t\t//\t\tAn object handle for the watch. The unwatch method of this object \n\t\t\t//\t\tcan be used to discontinue watching this property:\n\t\t\t//\t\t|\tvar watchHandle = obj.watch(\"foo\", callback);\n\t\t\t//\t\t|\twatchHandle.unwatch(); // callback won't be called now\n\t\t\t//\tcallback:\n\t\t\t//\t\tThe function to execute when the property changes. This will be called after\n\t\t\t//\t\tthe property has been changed. The callback will be called with the |this|\n\t\t\t//\t\tset to the instance, the first argument as the name of the property, the \n\t\t\t//\t\tsecond argument as the old value and the third argument as the new value.\n\t\t\n\t\t\tvar callbacks = this._watchCallbacks;\n\t\t\tif(!callbacks){\n\t\t\t\tvar self = this;\n\t\t\t\tcallbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){\n\t\t\t\t\tvar notify = function(propertyCallbacks){\n\t\t\t\t\t\tfor(var i = 0, l = propertyCallbacks && propertyCallbacks.length; i < l; i++){\n\t\t\t\t\t\t\ttry{\n\t\t\t\t\t\t\t\tpropertyCallbacks[i].call(self, name, oldValue, value);\n\t\t\t\t\t\t\t}catch(e){\n\t\t\t\t\t\t\t\tconsole.error(e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\tnotify(callbacks[name]);\n\t\t\t\t\tif(!ignoreCatchall){\n\t\t\t\t\t\tnotify(callbacks[\"*\"]); // the catch-all\n\t\t\t\t\t}\n\t\t\t\t}; // we use a function instead of an object so it will be ignored by JSON conversion\n\t\t\t}\n\t\t\tif(!callback && typeof name === \"function\"){\n\t\t\t\tcallback = name;\n\t\t\t\tname = \"*\";\n\t\t\t}\n\t\t\tvar propertyCallbacks = callbacks[name];\n\t\t\tif(typeof propertyCallbacks !== \"object\"){\n\t\t\t\tpropertyCallbacks = callbacks[name] = [];\n\t\t\t}\n\t\t\tpropertyCallbacks.push(callback);\n\t\t\treturn {\n\t\t\t\tunwatch: function(){\n\t\t\t\t\tpropertyCallbacks.splice($.inArray(propertyCallbacks, callback), 1);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\n\t});\n\n})(jQuery);"
  },
  {
    "path": "date.js",
    "content": "/*\t\n\n\tjQuery Date utility plugin by Peter Higgins (dante@dojotoolkit.org)\n\n\tBased on (actually, diretly ported from) Dojo date.js\n\n\tOriginal is (c) Dojo Foundation 2004-2010. Released under either AFL or new BSD, see:\n\thttp://dojofoundation.org/license for more information.\n\n*/\n(function(dojo){\n\n\tdojo.date = {\n\t\t// summary: Date manipulation utilities\n\t};\n\t\n\tdojo.date.getDaysInMonth = function(/*Date*/dateObject){\n\t\t//\tsummary:\n\t\t//\t\tReturns the number of days in the month used by dateObject\n\t\tvar month = dateObject.getMonth();\n\t\tvar days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n\t\tif(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number\n\t\treturn days[month]; // Number\n\t}\n\n\tdojo.date.isLeapYear = function(/*Date*/dateObject){\n\t\t//\tsummary:\n\t\t//\t\tDetermines if the year of the dateObject is a leap year\n\t\t//\tdescription:\n\t\t//\t\tLeap years are years with an additional day YYYY-02-29, where the\n\t\t//\t\tyear number is a multiple of four with the following exception: If\n\t\t//\t\ta year is a multiple of 100, then it is only a leap year if it is\n\t\t//\t\talso a multiple of 400. For example, 1900 was not a leap year, but\n\t\t//\t\t2000 is one.\n\n\t\tvar year = dateObject.getFullYear();\n\t\treturn !(year%400) || (!(year%4) && !!(year%100)); // Boolean\n\t}\n\n\t// FIXME: This is not localized\n\tdojo.date.getTimezoneName = function(/*Date*/dateObject){\n\t\t//\tsummary:\n\t\t//\t\tGet the user's time zone as provided by the browser\n\t\t// dateObject:\n\t\t//\t\tNeeded because the timezone may vary with time (daylight savings)\n\t\t//\tdescription:\n\t\t//\t\tTry to get time zone info from toString or toLocaleString method of\n\t\t//\t\tthe Date object -- UTC offset is not a time zone.  See\n\t\t//\t\thttp://www.twinsun.com/tz/tz-link.htm Note: results may be\n\t\t//\t\tinconsistent across browsers.\n\n\t\tvar str = dateObject.toString(); // Start looking in toString\n\t\tvar tz = ''; // The result -- return empty string if nothing found\n\t\tvar match;\n\n\t\t// First look for something in parentheses -- fast lookup, no regex\n\t\tvar pos = str.indexOf('(');\n\t\tif(pos > -1){\n\t\t\ttz = str.substring(++pos, str.indexOf(')'));\n\t\t}else{\n\t\t\t// If at first you don't succeed ...\n\t\t\t// If IE knows about the TZ, it appears before the year\n\t\t\t// Capital letters or slash before a 4-digit year \n\t\t\t// at the end of string\n\t\t\tvar pat = /([A-Z\\/]+) \\d{4}$/;\n\t\t\tif((match = str.match(pat))){\n\t\t\t\ttz = match[1];\n\t\t\t}else{\n\t\t\t// Some browsers (e.g. Safari) glue the TZ on the end\n\t\t\t// of toLocaleString instead of putting it in toString\n\t\t\t\tstr = dateObject.toLocaleString();\n\t\t\t\t// Capital letters or slash -- end of string, \n\t\t\t\t// after space\n\t\t\t\tpat = / ([A-Z\\/]+)$/;\n\t\t\t\tif((match = str.match(pat))){\n\t\t\t\t\ttz = match[1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Make sure it doesn't somehow end up return AM or PM\n\t\treturn (tz == 'AM' || tz == 'PM') ? '' : tz; // String\n\t}\n\n\t// Utility methods to do arithmetic calculations with Dates\n\n\tdojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){\n\t\t//\tsummary:\n\t\t//\t\tCompare two date objects by date, time, or both.\n\t\t//\tdescription:\n\t\t//\t\tReturns 0 if equal, positive if a > b, else negative.\n\t\t//\tdate1:\n\t\t//\t\tDate object\n\t\t//\tdate2:\n\t\t//\t\tDate object.  If not specified, the current Date is used.\n\t\t//\tportion:\n\t\t//\t\tA string indicating the \"date\" or \"time\" portion of a Date object.\n\t\t//\t\tCompares both \"date\" and \"time\" by default.\t One of the following:\n\t\t//\t\t\"date\", \"time\", \"datetime\"\n\n\t\t// Extra step required in copy for IE - see #3112\n\t\tdate1 = new Date(+date1);\n\t\tdate2 = new Date(+(date2 || new Date()));\n\n\t\tif(portion == \"date\"){\n\t\t\t// Ignore times and compare dates.\n\t\t\tdate1.setHours(0, 0, 0, 0);\n\t\t\tdate2.setHours(0, 0, 0, 0);\n\t\t}else if(portion == \"time\"){\n\t\t\t// Ignore dates and compare times.\n\t\t\tdate1.setFullYear(0, 0, 0);\n\t\t\tdate2.setFullYear(0, 0, 0);\n\t\t}\n\t\n\t\tif(date1 > date2){ return 1; } // int\n\t\tif(date1 < date2){ return -1; } // int\n\t\treturn 0; // int\n\t};\n\n\tdojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){\n\t\t//\tsummary:\n\t\t//\t\tAdd to a Date in intervals of different size, from milliseconds to years\n\t\t//\tdate: Date\n\t\t//\t\tDate object to start with\n\t\t//\tinterval:\n\t\t//\t\tA string representing the interval.\t One of the following:\n\t\t//\t\t\t\"year\", \"month\", \"day\", \"hour\", \"minute\", \"second\",\n\t\t//\t\t\t\"millisecond\", \"quarter\", \"week\", \"weekday\"\n\t\t//\tamount:\n\t\t//\t\tHow much to add to the date.\n\n\t\tvar sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112)\n\t\tvar fixOvershoot = false;\n\t\tvar property = \"Date\";\n\n\t\tswitch(interval){\n\t\t\tcase \"day\":\n\t\t\t\tbreak;\n\t\t\tcase \"weekday\":\n\t\t\t\t//i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true.\t see dojo.cldr.supplemental\n\n\t\t\t\t// Divide the increment time span into weekspans plus leftover days\n\t\t\t\t// e.g., 8 days is one 5-day weekspan / and two leftover days\n\t\t\t\t// Can't have zero leftover days, so numbers divisible by 5 get\n\t\t\t\t// a days value of 5, and the remaining days make up the number of weeks\n\t\t\t\tvar days, weeks;\n\t\t\t\tvar mod = amount % 5;\n\t\t\t\tif(!mod){\n\t\t\t\t\tdays = (amount > 0) ? 5 : -5;\n\t\t\t\t\tweeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);\n\t\t\t\t}else{\n\t\t\t\t\tdays = mod;\n\t\t\t\t\tweeks = parseInt(amount/5);\n\t\t\t\t}\n\t\t\t\t// Get weekday value for orig date param\n\t\t\t\tvar strt = date.getDay();\n\t\t\t\t// Orig date is Sat / positive incrementer\n\t\t\t\t// Jump over Sun\n\t\t\t\tvar adj = 0;\n\t\t\t\tif(strt == 6 && amount > 0){\n\t\t\t\t\tadj = 1;\n\t\t\t\t}else if(strt == 0 && amount < 0){\n\t\t\t\t// Orig date is Sun / negative incrementer\n\t\t\t\t// Jump back over Sat\n\t\t\t\t\tadj = -1;\n\t\t\t\t}\n\t\t\t\t// Get weekday val for the new date\n\t\t\t\tvar trgt = strt + days;\n\t\t\t\t// New date is on Sat or Sun\n\t\t\t\tif(trgt == 0 || trgt == 6){\n\t\t\t\t\tadj = (amount > 0) ? 2 : -2;\n\t\t\t\t}\n\t\t\t\t// Increment by number of weeks plus leftover days plus\n\t\t\t\t// weekend adjustments\n\t\t\t\tamount = (7 * weeks) + days + adj;\n\t\t\t\tbreak;\n\t\t\tcase \"year\":\n\t\t\t\tproperty = \"FullYear\";\n\t\t\t\t// Keep increment/decrement from 2/29 out of March\n\t\t\t\tfixOvershoot = true;\n\t\t\t\tbreak;\n\t\t\tcase \"week\":\n\t\t\t\tamount *= 7;\n\t\t\t\tbreak;\n\t\t\tcase \"quarter\":\n\t\t\t\t// Naive quarter is just three months\n\t\t\t\tamount *= 3;\n\t\t\t\t// fallthrough...\n\t\t\tcase \"month\":\n\t\t\t\t// Reset to last day of month if you overshoot\n\t\t\t\tfixOvershoot = true;\n\t\t\t\tproperty = \"Month\";\n\t\t\t\tbreak;\n\t//\t\tcase \"hour\":\n\t//\t\tcase \"minute\":\n\t//\t\tcase \"second\":\n\t//\t\tcase \"millisecond\":\n\t\t\tdefault:\n\t\t\t\tproperty = \"UTC\"+interval.charAt(0).toUpperCase() + interval.substring(1) + \"s\";\n\t\t}\n\n\t\tif(property){\n\t\t\tsum[\"set\"+property](sum[\"get\"+property]()+amount);\n\t\t}\n\n\t\tif(fixOvershoot && (sum.getDate() < date.getDate())){\n\t\t\tsum.setDate(0);\n\t\t}\n\n\t\treturn sum; // Date\n\t};\n\n\tdojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){\n\t\t//\tsummary:\n\t\t//\t\tGet the difference in a specific unit of time (e.g., number of\n\t\t//\t\tmonths, weeks, days, etc.) between two dates, rounded to the\n\t\t//\t\tnearest integer.\n\t\t//\tdate1:\n\t\t//\t\tDate object\n\t\t//\tdate2:\n\t\t//\t\tDate object.  If not specified, the current Date is used.\n\t\t//\tinterval:\n\t\t//\t\tA string representing the interval.\t One of the following:\n\t\t//\t\t\t\"year\", \"month\", \"day\", \"hour\", \"minute\", \"second\",\n\t\t//\t\t\t\"millisecond\", \"quarter\", \"week\", \"weekday\"\n\t\t//\t\tDefaults to \"day\".\n\n\t\tdate2 = date2 || new Date();\n\t\tinterval = interval || \"day\";\n\t\tvar yearDiff = date2.getFullYear() - date1.getFullYear();\n\t\tvar delta = 1; // Integer return value\n\n\t\tswitch(interval){\n\t\t\tcase \"quarter\":\n\t\t\t\tvar m1 = date1.getMonth();\n\t\t\t\tvar m2 = date2.getMonth();\n\t\t\t\t// Figure out which quarter the months are in\n\t\t\t\tvar q1 = Math.floor(m1/3) + 1;\n\t\t\t\tvar q2 = Math.floor(m2/3) + 1;\n\t\t\t\t// Add quarters for any year difference between the dates\n\t\t\t\tq2 += (yearDiff * 4);\n\t\t\t\tdelta = q2 - q1;\n\t\t\t\tbreak;\n\t\t\tcase \"weekday\":\n\t\t\t\tvar days = Math.round(dojo.date.difference(date1, date2, \"day\"));\n\t\t\t\tvar weeks = parseInt(dojo.date.difference(date1, date2, \"week\"));\n\t\t\t\tvar mod = days % 7;\n\n\t\t\t\t// Even number of weeks\n\t\t\t\tif(mod == 0){\n\t\t\t\t\tdays = weeks*5;\n\t\t\t\t}else{\n\t\t\t\t\t// Weeks plus spare change (< 7 days)\n\t\t\t\t\tvar adj = 0;\n\t\t\t\t\tvar aDay = date1.getDay();\n\t\t\t\t\tvar bDay = date2.getDay();\n\n\t\t\t\t\tweeks = parseInt(days/7);\n\t\t\t\t\tmod = days % 7;\n\t\t\t\t\t// Mark the date advanced by the number of\n\t\t\t\t\t// round weeks (may be zero)\n\t\t\t\t\tvar dtMark = new Date(date1);\n\t\t\t\t\tdtMark.setDate(dtMark.getDate()+(weeks*7));\n\t\t\t\t\tvar dayMark = dtMark.getDay();\n\n\t\t\t\t\t// Spare change days -- 6 or less\n\t\t\t\t\tif(days > 0){\n\t\t\t\t\t\tswitch(true){\n\t\t\t\t\t\t\t// Range starts on Sat\n\t\t\t\t\t\t\tcase aDay == 6:\n\t\t\t\t\t\t\t\tadj = -1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range starts on Sun\n\t\t\t\t\t\t\tcase aDay == 0:\n\t\t\t\t\t\t\t\tadj = 0;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range ends on Sat\n\t\t\t\t\t\t\tcase bDay == 6:\n\t\t\t\t\t\t\t\tadj = -1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range ends on Sun\n\t\t\t\t\t\t\tcase bDay == 0:\n\t\t\t\t\t\t\t\tadj = -2;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range contains weekend\n\t\t\t\t\t\t\tcase (dayMark + mod) > 5:\n\t\t\t\t\t\t\t\tadj = -2;\n\t\t\t\t\t\t}\n\t\t\t\t\t}else if(days < 0){\n\t\t\t\t\t\tswitch(true){\n\t\t\t\t\t\t\t// Range starts on Sat\n\t\t\t\t\t\t\tcase aDay == 6:\n\t\t\t\t\t\t\t\tadj = 0;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range starts on Sun\n\t\t\t\t\t\t\tcase aDay == 0:\n\t\t\t\t\t\t\t\tadj = 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range ends on Sat\n\t\t\t\t\t\t\tcase bDay == 6:\n\t\t\t\t\t\t\t\tadj = 2;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range ends on Sun\n\t\t\t\t\t\t\tcase bDay == 0:\n\t\t\t\t\t\t\t\tadj = 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t// Range contains weekend\n\t\t\t\t\t\t\tcase (dayMark + mod) < 0:\n\t\t\t\t\t\t\t\tadj = 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdays += adj;\n\t\t\t\t\tdays -= (weeks*2);\n\t\t\t\t}\n\t\t\t\tdelta = days;\n\t\t\t\tbreak;\n\t\t\tcase \"year\":\n\t\t\t\tdelta = yearDiff;\n\t\t\t\tbreak;\n\t\t\tcase \"month\":\n\t\t\t\tdelta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);\n\t\t\t\tbreak;\n\t\t\tcase \"week\":\n\t\t\t\t// Truncate instead of rounding\n\t\t\t\t// Don't use Math.floor -- value may be negative\n\t\t\t\tdelta = parseInt(dojo.date.difference(date1, date2, \"day\")/7);\n\t\t\t\tbreak;\n\t\t\tcase \"day\":\n\t\t\t\tdelta /= 24;\n\t\t\t\t// fallthrough\n\t\t\tcase \"hour\":\n\t\t\t\tdelta /= 60;\n\t\t\t\t// fallthrough\n\t\t\tcase \"minute\":\n\t\t\t\tdelta /= 60;\n\t\t\t\t// fallthrough\n\t\t\tcase \"second\":\n\t\t\t\tdelta /= 1000;\n\t\t\t\t// fallthrough\n\t\t\tcase \"millisecond\":\n\t\t\t\tdelta *= date2.getTime() - date1.getTime();\n\t\t}\n\n\t\t// Round for fractional values and DST leaps\n\t\treturn Math.round(delta); // Number (integer)\n\t};\n\n})(jQuery);"
  },
  {
    "path": "format.js",
    "content": "/**\n *       jquery.numberformatter - Formatting/Parsing Numbers in jQuery\n *       Completely changed by Peter Higgins (dante@dojotoolkit.org)\n *       Originally written by Michael Abernethy (mike@abernethysoft.com)\n *\n *       This plugin can be used to format numbers as text and parse text as Numbers\n *       Because we live in an international world, we cannot assume that everyone\n *       uses \",\" to divide thousands, and \".\" as a decimal point.\n *      \n *       The format() function will take the text within any selector by calling\n *       text() or val() on them, getting the String, and applying the specified format to it.\n *       It will return the jQuery object\n *      \n *       The parse() function will take the text within any selector by calling text()\n *       or val() on them, turning the String into a Number, and returning these\n *       values in a Number array.\n *       It WILL BREAK the jQuery chain, and return an Array of Numbers.\n *      \n *       Because there is limited use in a plugin that is unable to simply parse strings and numbers\n *       The parsing and formatting section has been broken out into $.formatNumber and $.parseNumber\n *      \n *       The syntax for the formatting is:\n *       0 = Digit\n *       # = Digit, zero shows as absent\n *       . = Decimal separator\n *       - = Negative sign\n *       , = Grouping Separator\n *       % = Percent (multiplies the number by 100)\n *       For example, a format of \"#,###.00\" and text of 4500.20 will\n *       display as \"4.500,20\" with a locale of \"de\", and \"4,500.20\" with a locale of \"us\"\n *      \n *      \n *       As of now, the only acceptable locales are \n *       United States -> \"us\"\n *       Arab Emirates -> \"ae\"\n *       Egypt -> \"eg\"\n *       Israel -> \"il\"\n *       Japan -> \"jp\"\n *       South Korea -> \"kr\"\n *       Thailand -> \"th\"\n *       China -> \"cn\"\n *       Hong Kong -> \"hk\"\n *       Taiwan -> \"tw\"\n *       Australia -> \"au\"\n *       Canada -> \"ca\"\n *       Great Britain -> \"gb\"\n *       India -> \"in\"\n *       Germany -> \"de\"\n *       Vietnam -> \"vn\"\n *       Spain -> \"es\"\n *       Denmark -> \"dk\"\n *       Austria -> \"at\"\n *       Greece -> \"gr\"\n *       Brazil -> \"br\"\n *       Czech -> \"cz\"\n *       France  -> \"fr\"\n *       Finland -> \"fi\"\n *       Russia -> \"ru\"\n *       Sweden -> \"se\"\n *       Switzerland -> \"ch\"\n *       \n *       TODO\n *       Separate positive and negative patterns separated by a \":\" (e.g. use (#,###) for accounting)\n *       More options may come in the future (currency)\n **/\n(function($){\n    \n    var defaults = {\n        parse:{\n            locale: \"us\",\n            decimalSeparatorAlwaysShown: false\n        },\n        format:{\n            format: \"#,###.00\",\n            locale: \"us\",\n            decimalSeparatorAlwaysShown: false\n        }\n    }\n    \n    var formatCodes = function(locale) {\n\n        var dec = \".\", group = \",\", neg = \"-\";\n        switch(locale.toLowerCase()){\n            case \"de\": case \"vn\": case \"es\": case \"dk\": case \"at\": case \"gr\": case \"br\":\n                dec = \",\"; group = \".\";\n                break;\n            case \"cz\": case \"fr\": case \"fi\": case \"ru\": case \"se\":\n                group = \" \"; dec = \",\";\n                break;\n            case \"ch\":\n                group = \"'\";\n                break;\n        }\n\n        return { group: group, dec: dec, neg: neg }\n        \n    };\n\n    var formatNumber = function(text, options, dontmix){\n        // summary: Format some plain number to a localized printable version\n        \n        var opts = dontmix ? (options || defaults.format) : $.extend({}, defaults.format, options),\n            d = dontmix || formatCodes(opts.locale),\n            dec = d.dec, group = d.group, neg = d.neg,\n            validFormat = \"0#-,.\", returnString = \"\"\n        ;\n\n        // strip all the invalid characters at the beginning and the end\n        // of the format, and we'll stick them back on at the end\n        // make a special case for the negative sign \"-\" though, so \n        // we can have formats like -$23.32\n        var prefix = \"\", negativeInFront = false;\n        for (var i = 0, l = opts.format.length; i < l; i++) {\n            if (validFormat.indexOf(opts.format.charAt(i)) == -1) {\n                prefix = prefix + opts.format.charAt(i);\n            } else if (i == 0 && opts.format.charAt(i) == '-'){\n                negativeInFront = true;\n                continue;                \n            } else {\n                break;\n            }\n        }\n\n        var suffix = \"\";\n        for (var i = opts.format.length - 1; i >= 0; i--) {\n            if (validFormat.indexOf(opts.format.charAt(i)) == -1){\n                suffix = opts.format.charAt(i) + suffix;\n            } else {\n                break;\n            }\n\n        }\n\n        opts.format = opts.format.substring(prefix.length);\n        opts.format = opts.format.substring(0, opts.format.length - suffix.length);\n\n        // now we need to convert it into a number\n        while (text.indexOf(group) > -1){\n            text = text.replace(group,'');\n        }\n           \n        var number = new Number(text.replace(dec,\".\").replace(neg,\"-\"));\n\n        // special case for percentages\n        if (suffix == \"%\") { number *= 100; }\n\n        var decimalValue = number % 1;\n        \n        if (opts.format.indexOf(\".\") > -1) {\n            var decimalPortion = dec;\n            var decimalFormat = opts.format.substring(opts.format.lastIndexOf(\".\") + 1);\n            var decimalString = new String(decimalValue.toFixed(decimalFormat.length));\n            decimalString = decimalString.substring(decimalString.lastIndexOf(\".\") + 1);\n            for (var i=0, l = decimalFormat.length; i < l; i++){\n                if (decimalFormat.charAt(i) == '#' && decimalString.charAt(i) != '0') {\n                    decimalPortion += decimalString.charAt(i);\n                    continue;\n                } else if (decimalFormat.charAt(i) == '#' && decimalString.charAt(i) == '0') {\n                    var notParsed = decimalString.substring(i);\n                    if (notParsed.match('[1-9]')) {\n                        decimalPortion += decimalString.charAt(i);\n                        continue;\n                    } else {\n                        break;\n                    }\n                } else if (decimalFormat.charAt(i) == \"0\") {\n                    decimalPortion += decimalString.charAt(i);\n                }\n            }\n            \n            returnString += decimalPortion;\n\n        } else {\n            number = Math.round(number);\n        }\n           \n        var ones = Math.floor(number);\n        if (number < 0){\n            ones = Math.ceil(number);\n        }\n\n        var onePortion = \"\";\n        if (ones == 0) {\n            onePortion = \"0\";\n        } else {\n            // find how many digits are in the group\n            var onesFormat = \"\";\n            if (opts.format.indexOf(\".\") == -1){\n                onesFormat = opts.format;\n            } else {\n                onesFormat = opts.format.substring(0, opts.format.indexOf(\".\"));\n            }\n\n            var oneText = new String(Math.abs(ones));\n            var groupLength = 9999;\n            if (onesFormat.lastIndexOf(\",\") != -1) {\n                groupLength = onesFormat.length - onesFormat.lastIndexOf(\",\") - 1;\n            }\n\n            var groupCount = 0;\n            for (var i = oneText.length - 1; i >- 1; i--) {\n                onePortion = oneText.charAt(i) + onePortion;\n                groupCount++;\n                if (groupCount == groupLength && i!=0) {\n                    onePortion = group + onePortion;\n                    groupCount = 0;\n                }\n\n            }\n        }\n        \n        returnString = onePortion + returnString;\n\n        // handle special case where negative is in front of the invalid\n        // characters\n        if (number < 0 && negativeInFront && prefix.length > 0) {\n            prefix = neg + prefix;\n        } else if (number < 0) {\n            returnString = neg + returnString;\n        }\n\n        if (!opts.decimalSeparatorAlwaysShown && returnString.lastIndexOf(dec) == returnString.length - 1) {\n            returnString = returnString.substring(0, returnString.length - 1);\n        }\n        \n        returnString = prefix + returnString + suffix;\n        return returnString;\n\n    };\n    \n    var parseNumber = function(text, options, dontmix){\n        \n        var opts = dontmix ? (options || defaults.parse) : $.extend({}, defaults.parse, options),   \n            formatData = dontmix || formatCodes(opts.locale),\n            dec = formatData.dec, group = formatData.group, neg = formatData.neg,\n            valid = \"1234567890.-\"\n        ;\n\n        // now we need to convert it into a number\n        while (text.indexOf(group) > -1){\n            text = text.replace(group,'');\n        }\n        \n        text = text.replace(dec,\".\").replace(neg,\"-\");\n        \n        var validText = \"\", hasPercent = false;\n        \n        if (text.charAt(text.length-1) == \"%\") { hasPercent = true }\n        for (var i = 0, l = text.length; i < l; i++) {\n            if (valid.indexOf(text.charAt(i)) > -1) {\n                validText += text.charAt(i);\n            }\n        }\n        \n        var number = new Number(validText);\n        if (hasPercent) {\n            number = number / 100;\n            number = number.toFixed(validText.length - 1);\n        }\n\n        return number;\n        \n    }\n    \n    // expose this in public:\n    $.parseNumber = parseNumber;\n    $.fn.parse = function(opts){\n        var o = $.extend({}, defaults.parse, opts), codez = formatCodes(o.locale);\n        return $.map(this, function(item){\n            var me = $(item), val = me[me.is(\":input\") ? \"val\" : \"text\"]();\n            return parseNumber(val, o, codez);\n        });\n    }\n    $.fn.parse.defaults = defaults.parse;\n    \n    $.formatNumber = formatNumber;\n    $.fn.format = function(opts){\n        var o = $.extend({}, defaults.format, opts), codez = formatCodes(o.locale);\n        return this.each(function(){\n            var me = $(this);\n            me[me.is(\":input\") ? \"val\" : \"text\" ](function(_, v){\n                return formatNumber(v, o, codez);\n            }); \n        });\n    }\n    $.fn.format.defaults = defaults.format;\n    \n})(jQuery);"
  },
  {
    "path": "hitch.js",
    "content": "/*\n\tjQuery.hitch() -  Advanced scope manipulation for jQuery \n\tversion: 0.1, Peter Higgins (dante at dojotoolkit.org)\n\n\t(c) 2004-2010 The Dojo Foundation - adapted from `dojo.hitch`\n\tEither AFL/New BSD license, see: http://dojotoolkit.org/license \n\n\tusage 1:\n\t\n\t\tvar obj = {\n\t\t\tattr: \"blah\",\n\t\t\tfunc: function(){\n\t\t\t\tconsole.log(this.attr);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// most useful example out of context, with setTimeout/Interval:\n\t\tsetInterval($.hitch(obj, \"func\"), 2100) // call obj.func() in scope of obj\n\t\tsetTimeout($.hitch(obj, function(){\n\t\t\tthis.attr = \"blargh\";\n\t\t\tthis.func();\n\t\t}), 2100);\n\t\n\tusage 2:\n\t\t\n\t\t// pseudo-class\n\t\tvar Thinger = function(){\n\t\t\tthis.foo = \"bar\";\n\t\t\tthis.bar = function(event){\n\t\t\t\t// super generic function to reuse lots\n\t\t\t\tthis.foo = $(event.target).attr(\"id\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tvar mine = new Thinger();\n\t\tvar yours = new Thinger();\n\t\t\n\t\t$(\".foo\").click($.hitch(mine, \"bar\"));\n\t\t$(mine).bind(\"bar\", $.hitch(yours, \"bar\"));\n\t\t\n*/\n;(function($){\n\n\t$.hitch = function(scope, method){\n\t\t// summary: Create a function that will only ever execute in a given scope\n\t\tif(!method){ method = scope; scope = null; }\n\t\tif(typeof method == \"string\"){\n\t\t\tscope = scope || window;\n\t\t\tif(!scope[method]){ throw(['method not found']); }\n\t\t\treturn function(){ return scope[method].apply(scope, arguments || []); };\n\t\t}\n\t\treturn !scope ? method : function(){ return method.apply(scope, arguments || []); };\n\t}\n\n})(jQuery);\n\n"
  },
  {
    "path": "pubsub.js",
    "content": "/*\t\n\n\tjQuery pub/sub plugin by Peter Higgins (dante@dojotoolkit.org)\n\n\tLoosely based on Dojo publish/subscribe API, limited in scope. Rewritten blindly.\n\n\tOriginal is (c) Dojo Foundation 2004-2010. Released under either AFL or new BSD, see:\n\thttp://dojofoundation.org/license for more information.\n\n*/\t\n\n;(function(d){\n\n\t// the topic/subscription hash\n\tvar cache = {};\n\n\td.publish = function(/* String */topic, /* Array? */args){\n\t\t// summary: \n\t\t//\t\tPublish some data on a named topic.\n\t\t// topic: String\n\t\t//\t\tThe channel to publish on\n\t\t// args: Array?\n\t\t//\t\tThe data to publish. Each array item is converted into an ordered\n\t\t//\t\targuments on the subscribed functions. \n\t\t//\n\t\t// example:\n\t\t//\t\tPublish stuff on '/some/topic'. Anything subscribed will be called\n\t\t//\t\twith a function signature like: function(a,b,c){ ... }\n\t\t//\n\t\t//\t|\t\t$.publish(\"/some/topic\", [\"a\",\"b\",\"c\"]);\n\t\tcache[topic] && d.each(cache[topic], function(){\n\t\t\tthis.apply(d, args || []);\n\t\t});\n\t};\n\n\td.subscribe = function(/* String */topic, /* Function */callback){\n\t\t// summary:\n\t\t//\t\tRegister a callback on a named topic.\n\t\t// topic: String\n\t\t//\t\tThe channel to subscribe to\n\t\t// callback: Function\n\t\t//\t\tThe handler event. Anytime something is $.publish'ed on a \n\t\t//\t\tsubscribed channel, the callback will be called with the\n\t\t//\t\tpublished array as ordered arguments.\n\t\t//\n\t\t// returns: Array\n\t\t//\t\tA handle which can be used to unsubscribe this particular subscription.\n\t\t//\t\n\t\t// example:\n\t\t//\t|\t$.subscribe(\"/some/topic\", function(a, b, c){ /* handle data */ });\n\t\t//\n\t\tif(!cache[topic]){\n\t\t\tcache[topic] = [];\n\t\t}\n\t\tcache[topic].push(callback);\n\t\treturn [topic, callback]; // Array\n\t};\n\n\td.unsubscribe = function(/* Array */handle){\n\t\t// summary:\n\t\t//\t\tDisconnect a subscribed function for a topic.\n\t\t// handle: Array\n\t\t//\t\tThe return value from a $.subscribe call.\n\t\t// example:\n\t\t//\t|\tvar handle = $.subscribe(\"/something\", function(){});\n\t\t//\t|\t$.unsubscribe(handle);\n\t\t\n\t\tvar t = handle[0];\n\t\tcache[t] && d.each(cache[t], function(idx){\n\t\t\tif(this == handle[1]){\n\t\t\t\tcache[t].splice(idx, 1);\n\t\t\t}\n\t\t});\n\t};\n\n})(jQuery);\n\n"
  },
  {
    "path": "tests/Stateful.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        \n        <title>Number Format Tests</title>\n        <script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js\"></script>\n        <script src=\"../Stateful.js\"></script>\n        <script>\n        \n            $(function(){\n\n                var thing = new $.Stateful();\n                thing.watch(\"bar\", function(){\n                    console.log(\"bar changed to\", this.get(\"bar\"));\n                });\n                thing.set(\"bar\", \"baz\");\n\n            });\n        \n        </script>\n        \n    </head>\n    <body>\n    </body>\n</html>"
  },
  {
    "path": "tests/format.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        \n        <title>Number Format Tests</title>\n        <script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js\"></script>\n        <script src=\"../format.js\"></script>\n        <script>\n        \n            $(function(){\n                \n                $(\"#foo, #bar\").format();\n\n                var o = $(\"#baz\");\n\n                var x = \"1234567\";\n                var xx = $.formatNumber(x);\n                \n                var y = \"1,234,567\";\n                var yy = $.parseNumber(y);\n                \n                o.append(\"<li>\" + xx + \"</li>\").append(\"<li>\" + yy + \"</li>\");\n            });\n        \n        </script>\n        \n    </head>\n    <body>\n        \n        <input id=\"foo\" value=\"1234567\">\n        \n        <div id=\"bar\">1234567</div>\n        \n        <ul id=\"baz\">\n            <li>outputs:</li>\n        </ul>\n        \n    </body>\n</html>"
  }
]