1 //##############################################################################
  2 // The $class Library
  3 // Copyright 2006, Jeff Lau
  4 // License: http://creativecommons.org/licenses/LGPL/2.1/
  5 // Contact: jlau@uselesspickles.com
  6 // Web:     www.uselesspickles.com
  7 //##############################################################################
  8 
  9 /**
 10  * @fileOverview
 11  * <p>
 12  * This is the debug version of the $class library, which contains tons of useful error checking. Include this
 13  * file during development or debugging. When it's time to deploy, be sure to switch over to including class.js
 14  * to get rid of the error checking overhead.
 15  * </p>
 16  *
 17  * <p>
 18  * <h2>
 19  * Error/Warning Logging
 20  * </h2>
 21  *   The debug version of the $class library attempts to log warning  and error
 22  * messages by methods "console.warn" and "console.error". These are logging
 23  * methods supported by the Firebug plugin for the Firefox web browser. If you
 24  * are debugging in a different environment and would like to log warnings/errors
 25  * in some way, create a global named "console" with methods named "warn" and
 26  * "error". These methods should expect to receive a single argument and should
 27  * log/display the value in whatever way is appropriate for your logging needs.
 28  * The logging methods should be defined before any calls to the $class
 29  * library to ensure all warnings are logged.
 30  * 
 31  * Example:
 32 <pre class="brush:js">
 33 var console = {
 34   warn: function(message) {
 35     alert("Warning: " + message);
 36   },
 37 
 38   error: function(message) {
 39     alert("Error: " + message);
 40   }
 41 };
 42 </pre>
 43  * </p>
 44  */
 45 
 46 /**
 47  * @namespace
 48  * This is where the $class library stores some of its implementation details to avoid polluting the global
 49  * scope.
 50  */
 51 $class_library = {
 52   /**
 53    * The version of the $class library.
 54    * @type String
 55    */
 56   version: "2.0b",
 57   
 58   /**
 59    * True if this is the debug version of the library.
 60    * @type Boolean
 61    */
 62   debug: true,
 63 
 64   _globalObject: this,
 65 
 66   _hasOwnProperty: Object.prototype.hasOwnProperty ?
 67     function (obj, prop) {
 68       return obj.hasOwnProperty(prop);
 69     }
 70     :
 71     function (obj, prop) {
 72       return (prop in obj) && obj.constructor.prototype[prop] !== obj[prop];
 73     },
 74 
 75   _warn: function() {
 76     var global = this._globalObject;
 77 
 78     if (global.console && global.console.warn) {
 79       var apply = Function.prototype.apply;
 80       apply.call(global.console.warn, global.console, arguments);
 81     }
 82   },
 83 
 84   _error: function() {
 85     var global = this._globalObject;
 86 
 87     if (global.console && global.console.error) {
 88       var apply = Function.prototype.apply;
 89       apply.call(global.console.error, global.console, arguments);
 90     }
 91 
 92     var message = "";
 93 
 94     for (var i = 0; i < arguments.length; ++i) {
 95       if (i) {
 96         message += "; ";
 97       }
 98 
 99       message += arguments[i];
100     }
101 
102     throw new Error(message);
103   },
104 
105   _copyObject: function(obj1, obj2) {
106     var result = (arguments.length == 2 && obj1) ? obj1 : {};
107     var source = ((arguments.length == 2) ? obj2 : obj1) || {};
108 
109     for (var i in source) {
110       result[i] = source[i];
111     }
112 
113     return result;
114   },
115 
116   _surrogateCtor: function() {
117   }
118 };
119 
120 //##############################################################################
121 
122 /**
123  * <p>
124  * Creates a namespace. Note that this documentation describes the behavior of $namespace when used as a method
125  * (without the "new" keyword). This should only be called as a method rather than as a constructor. Instances 
126  * of $namespace are created as a private implementation detail of $namespace being called as a method.
127  * </p>
128  * <p>
129  * A namespace is simply a named "container" for classes, methods, properties or even  other namespaces. 
130  * </p>
131  *
132  * <p>
133  * <h2>Example:</h2>
134 <pre class="brush:js">
135 $namespace("MyLibrary.UI.Forms");
136 
137 MyLibrary.UI.Forms.VERSION = 5;
138 
139 $class("MyLibrary.UI.Forms.Field", {
140   // ... properties, methods, etc.
141 });
142 
143 var field = new MyLibrary.UI.Forms.Field();
144 </pre>
145  * </p>
146  *
147  * @class 
148  * <p>
149  * This class represents a namespace, but its constructor is used as a function (without the "new" 
150  * keyword) to create a namespace. It is used as a constructor for private implementation purposes only. 
151  * </p>
152  *
153  * @constructor
154  *
155  * @param {String} name The name of the namespace. The name may describe a path of multiple nested 
156  * namespace/class/object names separated  by a period (.). All namespaces along the path will be created as 
157  * necessary. For example, a namespace name of "MyLibrary.UI.Forms" will create a namespace named "MyLibrary"
158  * that contains a namespace named "UI" which in turn contains a namespace named "Forms". If any of the 
159  * namespaces in the specified name path already exist, but were not created by $namespace, a warning will be 
160  * issued by the debug version of the $class library.
161  *
162  * @return {$namespace} the newly created (or pre-existing) namespace. If an entire path of namespaces was 
163  * created, only the last namespace in the path is returned.
164  */
165 function $namespace(name) {
166   // if being called as a constructor...
167   if (this instanceof $namespace) {
168     /**
169       * Overridden to return a string that identifies this namespace. This may be useful for debugging purposes. 
170       * This also gives each namespace a unique
171       * string representation for use as object keys.
172       * @return {String} a string in the format "[$namespace _name_]", where _name_ is the name of the 
173       * namespace, including the full path of parent namespaces.
174       */
175     this.toString = function() {
176        return "[$namespace " + name + "]";
177     };
178     
179     $class_library._surrogateCtor.prototype = this;
180     return new $class_library._surrogateCtor();
181   }
182 
183   var components = name.split(".");
184   var context = $class_library._globalObject;
185 
186   for (var i = 0; i < components.length; ++i) {
187     var nextContext = context[components[i]];
188 
189     if (!nextContext) {
190       nextContext = new $namespace(components.slice(0, i + 1).join("."));
191       context[components[i]] = nextContext;
192     } else if (!(nextContext instanceof $namespace)) {
193       $class_library._warn("Warning in $namespace(\"" + name + "\"): [" +
194                             components.slice(0, i + 1).join(".") +
195                             "] is already defined, but is not a namespace.");
196     }
197 
198     context = nextContext;
199   }
200 
201   return context;
202 }
203 
204 //##############################################################################
205 
206 /**
207  * <p>
208  * Creates a class with the specified name and properties. Note that this documentation describes the behavior 
209  * of $class when used as a method (without the "new" keyword). This should only be called as a method rather 
210  * than as a constructor. Instances of $class are created as a private implementation detail of $class being 
211  * called as a method.
212  * </p>
213  *
214  * <p>
215  * $class supports many features, such as abstract methods, implementing interfaces, easily calling an 
216  * overridden implementation of a method, and much more. See {@link $class.descriptor} for details.
217  * </p> 
218  *
219  * <p>
220  * The new class will have a static property named "$class" that is an instance of $class and can provide
221  * information about the class that was created by $class. Should I say "class" a few more times?
222  * </p> 
223  *
224  * <p>
225  * <h2>Example:</h2>
226 <pre class="brush:js">
227 $class("Sample", {
228   $constructor: function(arg) {
229     this._property = arg;
230   },
231   
232   getProperty: function() {
233     return this._property;
234   }
235 });
236 
237 var sample = new Sample("Hello World!");
238 
239 alert(sample.getProperty()); // alerts "Hello World"
240 
241 alert(sample instanceof Sample); // alerts "true"
242 </pre>
243  * </p>
244  *
245  * @class This class encapsulates information about a class, but its constructor is used as a function 
246  * (without the "new" keyword) to create a class. It is used as a constructor for private implementation 
247  * purposes only. Each class created by $class has a static property named "$class" that is an instance 
248  * of $class. $class instances can also be obtained by calling {@link #getClass}.
249  *
250  * @constructor
251  *
252  * @param {String} name The name of the class. The name may describe a path of multiple nested 
253  * namespace/class/object names separated by a period (.). The entire path to the class name is expected 
254  * to exist already. See {@link $namespace} for details about creating namespaces. 
255  *
256  * @param {$class.descriptor} descriptor An object containing the properties of the class, which can describe 
257  * methods, static methods, static properties, and more.
258  *
259  * @return {Function} The constructor for the newly created class.
260  */
261 function $class(name, descriptor) {
262   // if being called as a constructor...
263   if (this instanceof $class) {
264     if (!descriptor.calledFrom$class && !descriptor.calledFrom$class_adapt) {
265       $class._error(name, "Do not directly instantiate $class! Call $class as a function instead.");
266     }
267 
268     this._name = name;
269     this._isNative = descriptor.isNative;
270     this._ctor = descriptor.ctor;
271     this._baseCtor = descriptor.baseCtor || (this._ctor == Object ? null : Object);
272     this._isFinal = Boolean(descriptor.isFinal);
273     this._isSingleton = Boolean(descriptor.isSingleton);
274     this._isMultiton = Boolean(descriptor.isMultiton);
275     this._isAbstract = false;
276     this._interfaces = descriptor.interfaces || {};
277     this._abstractMethods = {};
278     this._finalMethods = {};
279     this._interfaceMethods = {};
280     this._children = [];
281 
282     // if not creating $class for Object...
283     if (this._ctor != Object) {
284       // if inheriting something other than Object...
285       if (this._baseCtor != Object) {
286         // if this $class object is being created internally by the $class function...
287         if (descriptor.calledFrom$class) {
288           // a 'surrogate' constructor used to create inheritance relationship
289           // without actually invoking the base class's constructor code
290           $class_library._surrogateCtor.prototype = this._baseCtor.prototype;
291           this._ctor.prototype = new $class_library._surrogateCtor();
292           this._ctor.prototype.constructor = this._ctor;
293         }
294 
295         // inherit info about the base class
296         var base$class = this._baseCtor.$class;
297 
298         if (base$class) {
299           this._interfaces = $class_library._copyObject(base$class._interfaces);
300           this._abstractMethods = $class_library._copyObject(base$class._abstractMethods);
301           this._finalMethods = $class_library._copyObject(base$class._finalMethods);
302 
303           base$class._children.push(this);
304         } else {
305           this._interfaces = {};
306           this._abstractMethods = {};
307           this._finalMethods = {};
308         }
309       }
310 
311       // store this class info on the prototype
312       this._ctor.prototype._$class = this;
313     }
314 
315     // Storing class info on prototype and constructor causes an IE leak; store created $class objects to clean up when
316     // unloading the page.
317     $class._cleanupCache.push(this);
318     return;
319   }
320 
321   if ($class_library._hasOwnProperty(descriptor, "$extends") && !descriptor.$extends) {
322     $class._propertyError(name, "$extends", "Cannot extend null. You probably forgot to include the JS file containing the declaration of the parent class.");
323   }
324 
325   var baseCtor = descriptor.$extends || Object;
326   var isSingleton = !!descriptor.$singleton;
327   var isMultiton = !!descriptor.$multiton;
328 
329   if (!(baseCtor instanceof Function)) {
330     $class._propertyError(name, "$extends", "Must be a constructor function");
331   }
332 
333   if (!baseCtor.$class) {
334     $class._propertyWarn(name, "$extends", "Extending a class that has no $class information. "
335                                          + "The class has been automatically adapted and given the name "
336                                          + "\"" + name + "$base\". Use $class.adapt() to pre-adapt "
337                                          + "the class and provide the correct name");
338     $class.adapt(baseCtor, name + "$base");
339   }
340 
341   if (baseCtor.$class && baseCtor.$class._isFinal) {
342     $class._propertyError(name, "$extends", "Cannot extend [" + baseCtor.$class.getName() + "] because its constructor is declared $final.");
343   }
344 
345   if (!isSingleton && baseCtor.$class && baseCtor.$class._isSingleton) {
346     $class._propertyError(name, "$extends", "Cannot extend [" + baseCtor.$class.getName() + "] because it is a singleton. Singletons can only be extended by other singletons.");
347   }
348 
349   if (!isMultiton && baseCtor.$class && baseCtor.$class._isMultiton) {
350     $class._propertyError(name, "$extends", "Cannot extend [" + baseCtor.$class.getName() + "] because it is a multiton. Multitons can only be extended by other multitons.");
351   }
352 
353   if (isSingleton && isMultiton) {
354     $class._propertyError(name, "$singleton/$multiton", "Cannot be both a singleton and a multiton");
355   }
356 
357   var ctorName = name.replace(/[^.]*\./g, "");
358   var ctor = descriptor.$constructor || descriptor[ctorName];
359   var isFinal = false;
360 
361   if (ctor instanceof $class._ModifiedProperty && ctor.getModifier() == "final") {
362     ctor = ctor.getValue();
363     isFinal = true;
364   }
365 
366   if (!ctor) {
367     $class_library._warn("No constructor specified for class [" + name + "]; using an empty default constructor.");
368     ctor = new Function();
369   }
370 
371   if (!(ctor instanceof Function)) {
372     $class._propertyError("$constructor", "Must be a function");
373   }
374 
375   ctor = $class._wrapCtorMethod(ctor, baseCtor);
376   ctor.$class = new $class(name, {ctor:ctor, baseCtor:baseCtor, isFinal:isFinal, isSingleton:isSingleton, isMultiton:isMultiton, calledFrom$class:true});
377 
378   if (isSingleton) {
379     var createInstance = (descriptor.$singleton.createInstance instanceof Function) ? descriptor.$singleton.createInstance : $class._createSingletonInstance_implementation;
380 
381     descriptor._$class_createSingletonInstance = $static(createInstance);
382     descriptor._$class_singletonInstance = $static(null);
383     descriptor.getInstance = $static($class._getSingletonInstance_implementation);
384   }
385 
386   if (isMultiton) {
387     var createInstance = (descriptor.$multiton.createInstance instanceof Function) ? descriptor.$multiton.createInstance : $class._createMultitonInstance_implementation;
388     var createCacheKey = (descriptor.$multiton.createCacheKey instanceof Function) ? descriptor.$multiton.createCacheKey : $class._createMultitonCacheKey_implementation;
389 
390     descriptor._$class_createMultitonInstance = $static(createInstance);
391     descriptor._$class_createMultitonCacheKey = $static(createCacheKey);
392     descriptor._$class_multitonInstances = $static({});
393     descriptor._$class_creatingMultitonInstance = $static({});
394     descriptor.getInstance = $static($class._getMultitonInstance_implementation);
395   }
396 
397   // implement interfaces
398   if (descriptor.$implements != null) {
399     var ifaces = descriptor.$implements;
400 
401     // convert to an array if it is a single object
402     if (!(ifaces instanceof Array)) {
403       ifaces = [ifaces];
404     }
405 
406     for (var i = 0, ifacesLength = ifaces.length; i < ifacesLength; ++i) {
407       // make sure the 'interface' to extend is really an interface
408       if (!(ifaces[i] instanceof $interface)) {
409         $class._propertyError(name, "$implements", "$interface or array of $interfaces expected");
410       }
411 
412       ctor.$class._implement(ifaces[i]);
413     }
414   }
415 
416   var specialProperties = {$constructor:true,$singleton:true,$multiton:true,$extends:true,$implements:true,$static:true};
417   var processedProperties = {};
418   specialProperties[ctorName] = true;
419 
420   // process all properties in the class descriptor
421   for (var propertyName in descriptor) {
422     // skip over special properties
423     if ($class_library._hasOwnProperty(specialProperties, propertyName)) {
424       continue;
425     }
426 
427     ctor.$class._processProperty(propertyName, descriptor[propertyName]);
428     processedProperties[propertyName] = true;
429   }
430 
431   if (!$class_library._hasOwnProperty(processedProperties, "toString") && $class_library._hasOwnProperty(descriptor, "toString")) {
432     ctor.$class._processProperty("toString", descriptor["toString"]);
433   }
434 
435   if (!$class_library._hasOwnProperty(processedProperties, "valueOf") && $class_library._hasOwnProperty(descriptor, "valueOf")) {
436     ctor.$class._processProperty("valueOf", descriptor["valueOf"]);
437   }
438 
439   // collect names of all interface methods that are not implemented
440   var missingInterfaceMethods = ctor.$class._getMissingInterfaceMethods();
441 
442   // if any interface methods are not implemented, we have a problem
443   if (missingInterfaceMethods.length != 0) {
444     var message = "The following interface methods must be implemented: ";
445 
446     for (var i = 0; i < missingInterfaceMethods.length; ++i) {
447       message += "[" + missingInterfaceMethods[i] + "] ";
448     }
449 
450     $class._error(name, message);
451   }
452 
453   // if any abstract methods are remaining, this class is abstract
454   for (var methodName in ctor.$class._abstractMethods) {
455     ctor.$class._isAbstract = true;
456     break;
457   }
458 
459   // set default toString method
460   if (ctor.prototype.toString == Object.prototype.toString) {
461     ctor.prototype.toString = new Function(
462       "return \"[object \" + $class.typeOf(this) + \"]\";"
463     );
464   }
465 
466   // store the constructor so it is accessible by the specified name
467   try {
468     var result = eval(name + " = ctor;");
469   } catch (error) {
470     $class._error(name, "Invalid class name: " + error.message);
471   }
472 
473   // call the static initializer
474   if (descriptor.$static instanceof Function) {
475     try {
476       descriptor.$static.call(ctor);
477     } catch (error) {
478       $class._error(name, "Error while executing static initializer: " + error.message);
479     }
480   } else if (descriptor.$static != null) {
481     $class._propertyError(name, "$static", "function expected");
482   }
483 
484   return result;
485 }
486 
487 //##############################################################################
488 
489 $class.prototype = {
490   //############################################################################
491 
492   /**
493    * Gets the full name of the class.
494    * @return {String} the full name of the class.
495    */
496   getName: function() {
497     return this._name;
498   },
499 
500   //############################################################################
501 
502   /**
503    * Returns true if this class is one of the standard JavaScript classes (Number, Function, etc).
504    * @return {Boolean} true if this class is one of the standard JavaScript classes.
505    */
506   isNative: function() {
507     return this._isNative;
508   },
509 
510   //############################################################################
511 
512   /**
513    * Returns the prototype object of this class.
514    * @return {Object} The class's prototype object.
515    */
516   getPrototype: function() {
517     return this._ctor.prototype;
518   },
519 
520   //############################################################################
521 
522   /**
523    * Gets the constructor for the class.
524    * @return {Function} the constructor for the class.
525    */
526   getConstructor: function() {
527     return this._ctor;
528   },
529 
530   //############################################################################
531 
532   /**
533    * Gets the $class object of this class's parent class.
534    * @return {$class} The $class object for this class's parent class. Returns null if this class is Object.
535    */
536   getSuperclass: function() {
537     return this._baseCtor ? this._baseCtor.$class : null;
538   },
539 
540   //############################################################################
541 
542   /**
543    * Tests if an object is an instance of this class.
544    * @param {Object} obj
545    * @return {Boolean} true if the object is an instance of this class, or any of its child classes.
546    */
547   isInstance: function(obj) {
548     return $class.instanceOf(obj, this._ctor);
549   },
550 
551   //############################################################################
552 
553   /**
554    * Tests if this class implements a specific interface.
555    * @param {$interface} iface
556    * @return {Boolean} true if this class implements the interface.
557    */
558   implementsInterface: function(iface) {
559     return $class_library._hasOwnProperty(this._interfaces, iface.getName());
560   },
561 
562   //############################################################################
563 
564   /**
565    * Overridden to return a string that identifies this $class object.
566    * @return {String} a string in the form "[$class _name_]", where _name_ is the full name of this class.
567    */
568   toString: function() {
569     return "[$class " + this._name + "]";
570   },
571 
572   //############################################################################
573 
574   _implement: function(iface) {
575     $class_library._copyObject(this._interfaces, iface._interfaces);
576     $class_library._copyObject(this._interfaceMethods, iface._methods);
577   },
578 
579   //############################################################################
580 
581   _processProperty: function(propertyName, value) {
582     var modifier = "";
583 
584     if (value instanceof $class._ModifiedProperty) {
585       modifier = value.getModifier();
586       value = value.getValue();
587 
588       if (value instanceof $class._ModifiedProperty) {
589         $class._propertyError(name, propertyName, "Only one modifier may be used per value");
590       }
591 
592       switch (modifier) {
593         case "static":
594           this._ctor[propertyName] = value;
595           return;
596 
597         case "abstract":
598         case "final":
599           if (!(value instanceof Function)) {
600             $class._propertyError(name, propertyName, "The $" + modifier + " modifier may only be applied to function values.");
601           }
602           break;
603       }
604     }
605 
606     // don't override anything that is final
607     if ($class_library._hasOwnProperty(this._finalMethods, propertyName)) {
608       var className = this._finalMethods[propertyName];
609       $class._propertyError(this._name, propertyName, "Cannot override a final property (originally declared final in class [" + className + "])");
610     }
611 
612     var isAbstract = false;
613 
614     switch (modifier) {
615       case "final":
616         this._finalMethods[propertyName] = this._name;
617         break;
618 
619       case "abstract":
620         this._abstractMethods[propertyName] = this._name;
621         value = $class._createAbstractMethod(this._name, propertyName);
622         isAbstract = true;
623         break;
624     }
625 
626     // if the property is overriding one from an inherited class...
627     if (propertyName in this._ctor.prototype) {
628       var baseValue = this._ctor.prototype[propertyName];
629 
630       // only allow functions to be overridden
631       if (!(baseValue instanceof Function) || !(value instanceof Function)) {
632         $class._propertyError(this._name, propertyName, "Only function properties can be overridden (with another function)");
633       } else {
634         if ($class._uses$base.test(value) && !$class_library._hasOwnProperty(this._abstractMethods, propertyName)) {
635           // wrap the method to give it access to the special $base property
636           value = $class._wrapExtendedMethod(value, baseValue);
637         }
638       }
639 
640       if (!isAbstract) {
641         delete this._abstractMethods[propertyName];
642       }
643     }
644 
645     this._ctor.prototype[propertyName] = value;
646   },
647 
648   //############################################################################
649 
650   _getMissingInterfaceMethods: function() {
651     var result = new Array();
652 
653     for (var methodName in this._interfaceMethods) {
654       if (!(this._ctor.prototype[methodName] instanceof Function)) {
655         var ifaceName = this._interfaceMethods[methodName];
656         result.push(ifaceName + "." + methodName);
657       }
658     }
659 
660     // don't need this info any more
661     delete this._interfaceMethods;
662 
663     return result;
664   }
665 
666   //############################################################################
667 };
668 
669 //##############################################################################
670 // List of $class objects created so they can be cleaned up when unloading the page
671 $class._cleanupCache = [];
672 
673 // using attachEvent because this is only needed to avoid memory leaks in IE, and only IE supports attachEvent.
674 if (typeof window != "undefined" && window.attachEvent) {
675   window.attachEvent('onunload', function() {
676     for (var i=0,clz; clz = $class._cleanupCache[i]; i++) {
677       delete clz._ctor.prototype._$class;
678       delete clz._ctor.$class;
679     }
680   });
681 }
682 
683 //##############################################################################
684 
685 $class._uses$base = /\bthis\.\$base\b/;
686 
687 //##############################################################################
688 
689 $class._error = function(name, message) {
690   $class_library._error("Error in $class(\"" + name + "\"" + ", ...): " + message);
691 };
692 
693 //##############################################################################
694 
695 $class._propertyError = function(name, propertyName, message) {
696   $class_library._error("Error in $class(\"" + name + "\"" + ", ...), property [" + propertyName + "]: " + message);
697 };
698 
699 //##############################################################################
700 
701 $class._propertyWarn = function(name, propertyName, message) {
702   $class_library._warn("Warning in $class(\"" + name + "\"" + ", ...), property [" + propertyName + "]: " + message);
703 };
704 
705 //##############################################################################
706 
707 $class._wrapCtorMethod = function(method, baseMethod) {
708   // automatically call the base class constructor if inheriting something
709   // other than Object and the constructor does not already call it
710   var call$base = !$class._uses$base.test(method) && baseMethod != Object;
711   var result = $class._createCtorWrapper(call$base);
712 
713   result._$class_wrappedMethod = method;
714   result.toString = $class._wrappedMethod_toString;
715 
716   return result;
717 };
718 
719 //##############################################################################
720 
721 $class._createCtorWrapper = function(call$base) {
722   return function() {
723     var method = arguments.callee;
724     var ctor = $class.getClass(this).getConstructor();
725 
726     // if this is the actual constructor for the object (not a base class constructor)...
727     if (ctor == method) {
728       if (method.$class._isAbstract) {
729         var message = "Attempted instantiation of the abstract class [" +
730                       method.$class._name + "]. Abstract methods: ";
731 
732         for (var methodName in method.$class._abstractMethods) {
733           message += "[" + method.$class._abstractMethods[methodName] + "." +
734                      methodName + "] ";
735         }
736 
737         $class_library._error(message);
738       }
739 
740       if (ctor.$class._isSingleton && !ctor._$class_creatingSingletonInstance) {
741         var message = "Attempted instantiation of the singleton class [" +
742                       ctor.$class._name + "]. Use " + ctor.$class._name + ".getInstance()";
743 
744         $class_library._error(message);
745       }
746 
747       if (ctor.$class._isMultiton && !ctor._$class_creatingMultitonInstance[ctor._$class_createMultitonCacheKey.apply(ctor, arguments)]) {
748         var message = "Attempted instantiation of the multiton class [" +
749                       ctor.$class._name + "]. Use " + ctor.$class._name + ".getInstance([constructor args])";
750 
751         $class_library._error(message);
752       }
753     }
754 
755     var previousBase = this.$base;
756     this.$base = method.$class._baseCtor;
757 
758     try {
759       if (call$base) {
760         this.$base.apply(this, arguments);
761       }
762 
763       return method._$class_wrappedMethod.apply(this, arguments);
764     } finally {
765       this.$base = previousBase;
766     }
767   };
768 };
769 
770 //##############################################################################
771 
772 $class._wrapExtendedMethod = function(method, baseMethod) {
773   var result = $class._createExtendedMethodWrapper();
774 
775   result._$class_wrappedMethod = method;
776   result._$class_baseMethod = baseMethod;
777   result.toString = $class._wrappedMethod_toString;
778 
779   return result;
780 };
781 
782 //##############################################################################
783 
784 $class._createExtendedMethodWrapper = function() {
785   return function() {
786     var method = arguments.callee;
787 
788     var previousBase = this.$base;
789     this.$base = method._$class_baseMethod;
790 
791     try {
792       return method._$class_wrappedMethod.apply(this, arguments);
793     } finally {
794       this.$base = previousBase;
795     }
796   };
797 };
798 
799 //##############################################################################
800 
801 $class._wrappedMethod_toString = function() {
802   return this._$class_wrappedMethod.toString();
803 };
804 
805 //##############################################################################
806 
807 $class._createAbstractMethod = function(name, propertyName) {
808   return function() {
809     $class_library._error("The abstract method [" + propertyName + "] declared " +
810                           "by class [" + name + "] was invoked on an object of type [" +
811                           $class.typeOf(this) + "].");
812   };
813 };
814 
815 //##############################################################################
816 
817 $class._getSingletonInstance_implementation = function() {
818   if (this._$class_singletonInstance) {
819     return this._$class_singletonInstance;
820   }
821 
822   if (this._$class_creatingSingletonInstance) {
823     $class_library._error(this.$class.getName() + ".getInstance(): infinite recursion encountered. Check for a call to getInstance that is called as a result of instantiating this class.");
824   }
825 
826   this._$class_creatingSingletonInstance = true;
827   this._$class_singletonInstance = this._$class_createSingletonInstance();
828   delete this._$class_creatingSingletonInstance;
829 
830   return this._$class_singletonInstance;
831 };
832 
833 //##############################################################################
834 
835 $class._createSingletonInstance_implementation = function() {
836   return new this();
837 };
838 
839 //##############################################################################
840 
841 $class._getMultitonInstance_implementation = function() {
842   var cacheKey = this._$class_createMultitonCacheKey.apply(this, arguments);
843   var result = this._$class_multitonInstances[cacheKey];
844 
845   if (result) {
846     return result;
847   }
848 
849   if ($class_library._hasOwnProperty(this._$class_creatingMultitonInstance, cacheKey)) {
850     $class_library._error(this.$class.getName() + ".getInstance(): infinite recursion encountered. Check for a call to getInstance that is called as a result of instantiating this class.");
851   }
852 
853   this._$class_creatingMultitonInstance[cacheKey] = true;
854   result = this._$class_multitonInstances[cacheKey] = this._$class_createMultitonInstance.apply(this, arguments);
855   delete this._$class_creatingMultitonInstance[cacheKey];
856 
857   return result;
858 };
859 
860 //##############################################################################
861 
862 $class._createMultitonInstance_implementation = function() {
863   return $class.instantiate(this, arguments);
864 };
865 
866 //##############################################################################
867 
868 $class._createMultitonCacheKey_implementation = function() {
869   return Array.prototype.join.call(arguments, "|");
870 };
871 
872 //##############################################################################
873 
874 $class._ModifiedProperty = function(modifier, value) {
875   this._modifier = modifier;
876   this._value = value;
877 };
878 
879 $class._ModifiedProperty.prototype = {
880   getModifier: function() {
881     return this._modifier;
882   },
883 
884   getValue: function() {
885     return this._value;
886   }
887 };
888 
889 //##############################################################################
890 
891 /**
892  * <p>
893  * Adapts a pre-existing class into the $class library framework. Use this to give a pre-existing class a 
894  * {@link $class} object so that it can fully participate in $class library features. For example, retroactively
895  * applied interfaces ({@link $interface#applyInterface}) will be automatically applied to all descendents
896  * of a class only if that class was defined by the $class function, or if the class was adapted with this method.
897  * </p>
898  *
899  * <p>
900  * If the specified class extends another class that does not exist within the $class framework, then that parent
901  * class will be automatically adapted, but with a name that is simply the specified name with "$base" appended
902  * (there's no way for me to know the actual name of the parent class). If you want each class in the heirarchy
903  * to have the correct name, then you must adapt each class, starting from the base class.
904  * </p>
905  *
906  * <p>
907  * Note that it is not necessary to adapt a class if you simply want to extend it using the $class library. When
908  * extending a class, it will be automatically adapted with a name made up of the child class's name with "$base"
909  * appended.
910  * </p>
911  *
912  * <p>
913  * If any {@link $interface}s had been applied ({@link $interface#applyInterface}) to the class or its prototype 
914  * before being adapted, it will be detected when adapting the class so that the adapted class and all of its 
915  * decendents will be considered to implement the interfaces.
916  * </p>
917  *
918  * <p>
919  * <h2>Example:</h2>
920 <pre class="brush:js">
921 var MyNamespace = {};
922 
923 MyNamespace.Sample = function(param) {
924   this._param = param;
925 }
926 
927 MyNamespace.Sample.prototype = {
928   getParam: function() {
929     return 
930   }
931 };
932 
933 $class.adapt(MyNamespace.Sample, "MyNamespace.Sample");
934 
935 alert(MyNamespace.Sample.$class.getName()); // alerts "MyNamespace.Sample"
936 </pre>
937  * </p>
938  *
939  * <p>
940  * <h2>Debug version warnings:</h2>
941  * <ul>
942  *   <li>No name is specified; an anonymous name will be supplied.</li>
943  *   <li>Base class of the adapted class is automatically adapted.</li>
944  * </ul>
945  * </p>
946  *
947  * @function
948  * @param {Function} ctor The constructor function of the class to be adapted.
949  * @param {String} name (optional) The full name of the class. If not specified, an anonymous name will be 
950  * generated.
951  * @return {Boolean} true if the class was adapted, false if the class is already within the $class library 
952  * framework at the time this method was called.
953  */
954 $class.adapt = (function() {
955   var unnamedCount = 0;
956 
957   return function(ctor, name, isNative) {
958     if (ctor.$class) {
959       return false;
960     }
961 
962     var baseCtor = ctor.prototype.constructor;
963 
964     if (ctor != Object) {
965       var hold = ctor.prototype.constructor;
966 
967       if (delete ctor.prototype.constructor) {
968         baseCtor = ctor.prototype.constructor;
969         ctor.prototype.constructor = hold;
970       }
971     }
972 
973     if (!name) {
974       name = "$unnamed_adapted_class_" + (unnamedCount++);
975       
976       $class_library._warn("Warning in $class.adapt([function]): "
977                          + "No name was specified. "
978                          + "Defaulting the name to \"" + name + "\".");      
979     }
980 
981     if (baseCtor == ctor || !baseCtor) {
982       baseCtor = Object;
983     } else if (!baseCtor.$class) {
984       $class_library._warn("Warning in $class.adapt([function], \"" + name + "\"): "
985                          + "The class being adapted extends a class that must also be adapted. "
986                          + "It will be given the name \"" + name + "$base\". "
987                          + "Pre-adapt the base class to give it the correct name.");
988       $class.adapt(baseCtor, name + "$base");
989     }
990 
991     var interfaces = ctor.prototype._$class_interfaces;
992     delete ctor.prototype._$class_interfaces;
993     
994     ctor.$class = new $class(name, {
995       ctor: ctor,
996       baseCtor: baseCtor,
997       isNative: isNative,
998       interfaces: interfaces,
999       calledFrom$class_adapt: true
1000     });
1001 
1002     return true;
1003   };
1004 })();
1005 
1006 //##############################################################################
1007 
1008 /**
1009  * <p>
1010  * Gets the value of a fully qualified name, possibly nested within one or more {@link $namespace}s or
1011  * namespace-like objects. Does not cause an error if any object along the path is undefined/null. Simply
1012  * returns undefined of the specified name could not be reached.
1013  * </p>
1014  *
1015  * <p>
1016  * <h2>Example:</h2>
1017 <pre class="brush:js">
1018 $namespace("nested.namespace");
1019 
1020 nested.namespaces.SOME_VALUE = 10;
1021 
1022 alert($class.resolve("nested.namespace.SOME_VALUE")) // alerts "10"
1023 
1024 alert($class.resolve("nonexistant.namespace.SOME_VALUE")) // alerts "undefined"
1025 </pre>
1026  * </p>
1027  *
1028  * @param {String} name The fully qualified name of some object/value.
1029  * @return {mixed} the value found at the specified name, or undefined if it could not be reached.
1030  */
1031 $class.resolve = function(name) {
1032   var components = name.split(".");
1033   var context = $class_library._globalObject;
1034 
1035   for (var i = 0; i < components.length; ++i) {
1036     if (context == null) {
1037     $class_library._warn("$class.resolve(\"" + name + "\") failed: "
1038                         + components.slice(0, i).join(".") + " is null/undefined.");
1039       return undefined;
1040     }
1041 
1042     var context = context[components[i]];
1043   }
1044 
1045   return context;
1046 };
1047 
1048 //##############################################################################
1049 
1050 /**
1051  * <p>
1052  * Tests if an object is an implementation of an {@link $interface}. This method only tests if the object has 
1053  * already been marked as being an implementation of the interface; it does not actually analyze the object to
1054  * determine if all interface methods are implemented. See {@link $class.descriptor#$implements} and 
1055  * {@link $interface#applyInterface} for performing the work of marking an object as implementing an interface.
1056  * </p>
1057  *
1058  * @param {mixed} obj any object or primitive.
1059  * @param {$interface} iface any interface.
1060  * @return {Boolean} true if the object implements the interface.
1061  */
1062 $class.implementationOf = function(obj, iface) {
1063   if (obj._$class_interfaces && $class_library._hasOwnProperty(obj._$class_interfaces, iface.getName())) {
1064     return true;
1065   }
1066 
1067   return $class.getClass(obj).implementsInterface(iface);
1068 };
1069 
1070 //##############################################################################
1071 
1072 /**
1073  * <p>
1074  * Tests if an object is an instance of a class or an implementation of an interface.
1075  * </p>
1076  *
1077  * <p>
1078  * This method has special handling of primitive JavaScript values to consider them to be instances of their
1079  * corresponding classes. For example, <code class="brush:js">var x = 5; $class.instanceOf(x, Number)</code>
1080  * will return true, but <code class="brush:js">var x = 5; x instanceof Number</code> will return false.
1081  * </p>
1082  * 
1083  * <p>
1084  * The $class library supplies dummy classes {@link Null} and {@link Undefined}. This method will identify
1085  * <em>null</em> and <em>undefined</em> as "instances" of those classes (respectively).
1086  * </p>
1087  *
1088  * <p>
1089  * If you do not need the special handling of primitive values, and the <em>type</em> is never going to be an
1090  * interface, then you can simply use the JavaScript <em>instanceof</em> operator for any classes created by 
1091  * {@link $class}.
1092  * </p>
1093  *
1094  * @param {mixed} obj any object or primitive.
1095  * @param {Function|$interface} type A constructor function of some class, or an interface.
1096  * @return {Boolean} true if the object is an instance of the specified class (or implementation of the specified
1097  * interface).
1098  */
1099 $class.instanceOf = function(obj, type) {
1100   if (type instanceof $interface) {
1101     return $class.implementationOf(obj, type);
1102   }
1103 
1104   switch (typeof obj) {
1105     case "object":
1106       return (obj instanceof type) ||
1107              // special case for null
1108              (obj === null && type == Null);
1109 
1110     case "number":
1111       return (type == Number);
1112 
1113     case "string":
1114       return (type == String);
1115 
1116     case "boolean":
1117       return (type == Boolean);
1118 
1119     case "function":
1120     default:
1121       return (obj instanceof type);
1122 
1123     case "undefined":
1124       return (type == Undefined);
1125   }
1126 };
1127 
1128 //##############################################################################
1129 
1130 /**
1131  * <p>
1132  * Gets the name of the class of the specified object. If the object is not an instance of a class that was created
1133  * by {@link $class} or adapted with {@link $class#adapt}, then it will be identified generically as "Object".
1134  * </p>
1135  *
1136  * <p>
1137  * JavaScript primitive values will be reported as being instances of their corresponding classes.
1138  * </p>
1139  * 
1140  * <p>
1141  * The $class library supplies dummy classes {@link Null} and {@link Undefined}. This method will identify
1142  * <em>null</em> and <em>undefined</em> as "Null" and "Undefined" (respectively).
1143  * </p>
1144  *
1145  * <p>
1146  * <h2>Example:</h2>
1147 <pre class="brush:js">
1148 $namespace("nested.namespace");
1149 
1150 $class("nested.namespace.Example", {});
1151 
1152 var example = new Example();
1153 
1154 alert($class.typeOf(example)) // alerts "nested.namespace.Example"
1155 alert($class.typeOf(5)) // alerts "5"
1156 alert($class.typeOf(null)) // alerts "Null"
1157 </pre>
1158  * </p>
1159  *
1160  * @param {mixed} obj any object or primitive.
1161  * @return {String} the name of the class of the object.
1162  */
1163 $class.typeOf = function(obj) {
1164   return $class.getClass(obj).getName();
1165 };
1166 
1167 //##############################################################################
1168 
1169 /**
1170  * <p>
1171  * Gets the {@link $class} object that represents the class of the specified object. If the object is not an 
1172  * instance of a class that was created by {@link $class} or adapted with {@link $class#adapt}, then Object's
1173  * $class object will be returned.
1174  * </p>
1175  *
1176  * <p>
1177  * For JavaScript primitive valuesthe $class objects of of their corresponding classes will be returned.
1178  * </p>
1179  *
1180  * <p>
1181  * For <em>null</em> and <em>undefined</em>, the $class objects for the dummy classes {@link Null} and 
1182  * {@link Undefined} will be returned (respectively).
1183  * </p>
1184  *
1185  * @param {mixed} obj any object or primitive.
1186  * @return {$class} The object's class's $class object.
1187  */
1188 $class.getClass = function(obj) {
1189   if (obj == null) {
1190     if (obj === undefined) {
1191       return Undefined.$class;
1192     }
1193 
1194     return Null.$class;
1195   }
1196 
1197   return obj._$class || Object.$class;
1198 };
1199 
1200 //##############################################################################
1201 
1202 /**
1203  * <p>
1204  * Creates a new instance of a specified class using an array of arguments.
1205  * </p>
1206  *
1207  * <p>
1208  * For "native" JavaScript classes (those defined by the ECMAScript spec, such as Number, RegExp, etc), the 
1209  * result of calling the constructor as a function will be returned. For classes that have corresponding primitive
1210  * types (Number, Boolean, String), this means that a primitive value will be returned instead of an instance of
1211  * the class. This is usually preferred for reasons such as instances of Strings, Boolean and Number always
1212  * evaluating to a boolean value of <em>true</em> even if their values are false-like.
1213  * </p>
1214  *
1215  * <p>
1216  * <h2>Example:</h2>
1217 <pre class="brush:js">
1218 $class("Person", {
1219   $constructor: function(firstName, lastName) {
1220     this._firstName = firstName;
1221     this._lastName) = lastName);
1222   },
1223   
1224   getFullName: function() {
1225     return this._firstName + " " + this._lastName;
1226   }
1227 });
1228 
1229 var person = $class.instantiate(Person, ["John", "Doe"]);
1230 alert(person.getFullName()) // alerts "John Doe"
1231 
1232 var number = $class.instantiate(Number, ["123"]);
1233 alert(number) // alerts "123"
1234 alert(typeof number) // alerts "number"
1235 alert(number instanceof Number) // alerts "false"
1236 </pre>
1237  * </p>
1238  *
1239  * @param {Function} ctor The constructor function for some class.
1240  * @param {Array} args An array of argument values to be passed to the constructor.
1241  * @return {mixed} A new instance of the specified class (or a primitive value).
1242  */
1243 $class.instantiate = function(ctor, args) {
1244   if (ctor.$class && ctor.$class.isNative()) {
1245     return ctor.apply($class_library._globalObject, args);
1246   } else {
1247     $class_library._surrogateCtor.prototype = ctor.prototype;
1248     var result = new $class_library._surrogateCtor();
1249     ctor.apply(result, args);
1250 
1251     return result;
1252   }
1253 };
1254 
1255 //##############################################################################
1256 
1257 /**
1258  * <p>
1259  * Creates an interface with the specified name and properties. Note that this documentation describes the behavior 
1260  * of $interface when used as a method (without the "new" keyword). This should only be called as a method rather 
1261  * than as a constructor. Instances of $interface are created as a private implementation detail of $interface being 
1262  * called as a method.
1263  * </p>
1264  * 
1265  * <p>
1266  * An interface describes methods that must be implemented by a class that claims to implement the interface.
1267  * Interfaces can also extend other interfaces and contain static properties/methods. 
1268  * See {@link $interface.descriptor} for details.
1269  * </p> 
1270  *
1271  * @class This class encapsulates information about an interface, but its constructor is used as a function 
1272  * (without the "new" keyword) to create an interface. It is used as a constructor for private implementation 
1273  * purposes only.
1274  *
1275  * @constructor
1276  *
1277  * @param {String} name The name of the interface. The name may describe a path of multiple nested 
1278  * namespace/class/object names separated by a period (.). The entire path to the interface name is expected 
1279  * to exist already. See {@link $namespace} for details about creating namespaces. 
1280  *
1281  * @param {$interface.descriptor} descriptor An object containing the properties of the interface, which can 
1282  * describe methods, static methods, static properties, and more.
1283  *
1284  * @return {$interface} The newly created interface.
1285  */
1286 function $interface(name, descriptor) {
1287   // if being called as a constructor...
1288   if (this instanceof $interface) {
1289     if (!descriptor.calledFrom$interface) {
1290       $class_library._error("Error in attempt to define interface [" + name + "]: "
1291                           + "Do not directly instantiate $interface! Call $interface as a function instead.");
1292     }
1293 
1294     this._name = name;
1295     this._methods = {};
1296     this._methodsArray = null;
1297     this._interfaces = {};
1298     this._interfaces[name] = this;
1299     return;
1300   }
1301 
1302   var iface = new $interface(name, {calledFrom$interface: true});
1303 
1304   // extend interfaces
1305   if ($class_library._hasOwnProperty(descriptor, "$extends")) {
1306     var ifaces = descriptor.$extends;
1307 
1308     // convert to an array if it is a single object
1309     if (!(ifaces instanceof Array)) {
1310       ifaces = [ifaces];
1311     }
1312 
1313     for (var i = 0, ifacesLength = ifaces.length; i < ifacesLength; ++i) {
1314       // make sure the 'interface' to extend is really an interface
1315       if (!(ifaces[i] instanceof $interface)) {
1316         if (ifaces[i] == null) {
1317           $interface._propertyError(name, "$extends[" + i +"]", "Cannot extend null. You probably forgot to include the JS file containing the declaration of the parent class.");
1318         } else {
1319           $interface._propertyError(name, "$extends[" + i +"]", "$interface or array of $interfaces expected");
1320         }
1321       }
1322 
1323       iface._extend(ifaces[i]);
1324     }
1325   }
1326 
1327   var specialProperties = {$extends:true};
1328   var invalidProperties = {$constructor:true,$implements:true,$static:true};
1329 
1330   // process all properties in the descriptor
1331   for (var propertyName in descriptor) {
1332     // skip over the special properties
1333     if ($class_library._hasOwnProperty(specialProperties, propertyName)) {
1334       continue;
1335     }
1336 
1337     // check for invalid properties
1338     if ($class_library._hasOwnProperty(invalidProperties, propertyName)) {
1339       $interface._propertyError(name, propertyName, "invalid property for an $interface");
1340     }
1341 
1342     var value = descriptor[propertyName];
1343 
1344     if (value instanceof $class._ModifiedProperty && value.getModifier() == "static") {
1345       iface._addStatic(propertyName, value.getValue());
1346     } else if (value instanceof Function) {
1347       iface._addMethod(propertyName);
1348     } else {
1349       $interface._propertyError(name, propertyName, "Function or static value expected");
1350     }
1351   }
1352 
1353   // store the interface so it can be referenced by the specified name
1354   try {
1355     return eval(name + " = iface;");
1356   } catch (error) {
1357     $interface._error(name, "Invalid interface name: " + error.message);
1358   }
1359 }
1360 
1361 //##############################################################################
1362 
1363 $interface.prototype = {
1364   //############################################################################
1365 
1366   /**
1367    * Gets the name of the interface.
1368    * @return {String} the full name of the interface.
1369    */
1370   getName: function() {
1371     return this._name;
1372   },
1373 
1374   //############################################################################
1375 
1376   /**
1377    * Tests if the interface (or any inherited interfaces) contains a method. 
1378    * @param {String} methodName the name of a potential method.
1379    * @return {Boolean} true if this interface has a method with the specified name.
1380    */
1381   hasMethod: function(methodName) {
1382     return Boolean(this._methods[methodName]);
1383   },
1384 
1385   //############################################################################
1386 
1387   /**
1388    * Gets a list of all methods in this interface (including methods of inherited interfaces).
1389    * @return {String[]} an array of method names.
1390    */
1391   getMethods: function() {
1392     if (!this._methodsArray) {
1393       this._methodsArray = [];
1394 
1395       for (var methodName in this._methods) {
1396         this._methodsArray.push(methodName);
1397       }
1398     }
1399 
1400     return this._methodsArray;
1401   },
1402 
1403   //############################################################################
1404 
1405   /**
1406    * <p>
1407    * Applies this interface to the specified object or class. This marks the object or class as implementing this
1408    * interface. The debug version of the $class library will verify that all interface methods are actually 
1409    * implemented by the object or class.
1410    * </p>
1411    *
1412    * <p>
1413    * This method has two intended uses:
1414    * <ol>
1415    *   <li>
1416    *     Retroactively mark a class as implementing an interface. This allows you to avoid modifying the definition
1417    *     of a class. You can pass either the constructor of the class, or the class's $class object 
1418    *     to applyInterface. Interfaces can be applied to classes that are not within the $class framework by 
1419    *     applying the interface to the class's constructor, but requires that all interface methods are implemented
1420    *     on the class's prototype rather than assigned directly to properties in the constructor. The interface
1421    *     information will be preserved if the class is later adapted into the $class framework via
1422    *     {@link $class.adapt}.
1423    *   </li>
1424    *   <li>
1425    *     Mark a specific object as implementing an interface. This could be an anonymous object, which would be 
1426    *     like creating an anonymous implementation of the interface. IMPORTANT: Interfaces cannot be applied to
1427    *     directly to functions. Doing so will be interpreted as an attempt to apply the interface to a class that
1428    *     is not within the $class framework (see above).
1429    *   </li>
1430    * </ol>
1431    * </p>
1432    *
1433    * <p>
1434    * When used to apply an interface to an object (not a class), be aware that a property (_$class_interfaces) will
1435    * be added to the object. If the object cannot be polluted with an extra property, then use {@link #wrapObject}.
1436    * </p>
1437    *
1438    * <p>
1439    * <h2>Debug version errors:</h2>
1440    * <ul>
1441    *   <li>Interface method not implemented in the class or object. The error message will list all methods not 
1442    *       implemented.</li>
1443    * </ul>
1444    * </p>
1445    *
1446    * @param {$class|Function|Object} obj The constructor or $class object of a class 
1447    * that implements all methods of this interface (to apply the interface to a class), or any object that 
1448    * implements all methods of this interface to apply the interface to that particular object.
1449    * @return {$class|Function|Object} The <em>obj</em> argument.
1450    */
1451   applyInterface: function(obj) {
1452     var classInfo = obj instanceof $class ? obj : obj.$class;
1453 
1454     if (classInfo) {
1455       obj = classInfo.getPrototype();
1456     } else if (obj.constructor == Function) {
1457       obj = obj.prototype;
1458     }
1459 
1460     var missingInterfaceMethods = new Array();
1461 
1462     for (var methodName in this._methods) {
1463       if (!(obj[methodName] instanceof Function)) {
1464         var ifaceName = this._methods[methodName];
1465         missingInterfaceMethods.push(ifaceName + "." + methodName);
1466       }
1467     }
1468 
1469     if (missingInterfaceMethods.length > 0) {
1470       var message = "Error in " + this.getName() + ".applyInterface(" + (classInfo ? classInfo.getName() : "[object]") + "); The following interface methods must be implemented: ";
1471 
1472       for (var i = 0; i < missingInterfaceMethods.length; ++i) {
1473         message += "[" + missingInterfaceMethods[i] + "] ";
1474       }
1475 
1476       $class_library._error(name, message);
1477     }
1478 
1479     if (classInfo) {
1480       this._applyInterface([classInfo]);
1481     } else {
1482       if (!obj._$class_interfaces) {
1483         obj._$class_interfaces = {};
1484       }
1485 
1486       for (var ifaceName in this._interfaces) {
1487         obj._$class_interfaces[ifaceName] = this._interfaces[ifaceName];
1488       }
1489     }
1490 
1491     return obj;
1492   },
1493 
1494   //############################################################################
1495 
1496   _applyInterface: function(classes) {
1497     for (var i = 0, classInfo; classInfo = classes[i]; ++i) {
1498       for (var ifaceName in this._interfaces) {
1499         classInfo._interfaces[ifaceName] = this._interfaces[ifaceName];
1500       }
1501 
1502       this._applyInterface(classInfo._children);
1503     }
1504   },
1505 
1506   //############################################################################
1507 
1508   /**
1509    * <p>
1510    * Creates an anonymous implementation of this interface whose methods are all implemented by simply calling the 
1511    * method of the name on the specified object. This may be an alternative to applying the interface directly to 
1512    * the object, which will add a property to the object that may be undesirable 9see {@link #applyInterface}. The 
1513    * debug version of the $class library will verify that the object implements all methods of this interface.
1514    * </p>
1515    *
1516    * @param {Object} obj An object that implements all methods of this interface.
1517    * @return {Object} a new object that implements this interface by calling methods on the <em>obj</em> argument. 
1518    */
1519   wrapObject: function(obj) {
1520     var result = {_obj: obj};
1521 
1522     result.toString = new Function("return '[" + $class.typeOf(obj) + " wrapped by " + this.getName() + "]';");
1523 
1524     for (var methodName in this._methods) {
1525       // Only create the interface method if a corresponding method exists on the object. This allows applyInterface to fail.
1526       if (typeof obj[methodName] == "function") {
1527         result[methodName] = new Function("return this._obj['" + methodName + "'].apply(this._obj, arguments);");
1528       }
1529     }
1530 
1531     return this.applyInterface(result);
1532   },
1533 
1534 //############################################################################
1535 
1536   /**
1537    * Overridden to return a string that identifies this $interface.
1538    * @return {String} a string in the form "[$interface _name_]", where _name_ is the full name of this interface.
1539    */
1540   toString: function() {
1541     return "[$interface " + this._name + "]";
1542   },
1543 
1544   //############################################################################
1545 
1546   _extend: function(iface) {
1547     $class_library._copyObject(this._methods, iface._methods);
1548     $class_library._copyObject(this._interfaces, iface._interfaces);
1549   },
1550 
1551   //############################################################################
1552 
1553   _addStatic: function(propertyName, value) {
1554     this[propertyName] = value;
1555   },
1556 
1557   //############################################################################
1558 
1559   _addMethod: function(propertyName) {
1560     this._methods[propertyName] = this._name;
1561   }
1562 
1563   //############################################################################
1564 };
1565 
1566 //##############################################################################
1567 
1568 $interface._error = function(name, message) {
1569   $class_library._error("Error in $interface(\"" + name + "\"" + ", ...): " + message);
1570 };
1571 
1572 //##############################################################################
1573 
1574 $interface._propertyError = function(name, propertyName, message) {
1575   $class_library._error("Error in $interface(\"" + name + "\"" + ", ...), property [" + propertyName + "]: " + message);
1576 };
1577 
1578 //##############################################################################
1579 
1580 /**
1581  * <p>
1582  * Creates an abstract method in a class. This is a property modifier for use within a 
1583  * {@link $class.descriptor}. 
1584  * </p>
1585  * <p>
1586  * An abstract method has no implementation and prevents the class from being instantiated. A class with
1587  * any abstract methods is inherently abstract; the class itself does not need to be (and cannot be) marked 
1588  * as absract. Any class that extends an abstract class is also abstract, unless it implements (overrides) all
1589  * inherited abstract methods. The abstract modifier may only be applied to non-{@link $final} and 
1590  * non-{@link $static} methods.
1591  * </p>
1592  *
1593  * <p>
1594  * <h2>Debug version errors:</h2>
1595  * <ul>
1596  *   <li>Attempt to instantiate an abstract class. The error message will indicate the abstract class and will 
1597          list all abstract methods and from which class they were inherited.</li>
1598  *   <li>Attempt to create an abstract property (not a method). The error message will indicate the class and 
1599  *       property name.</li>
1600  * </ul>
1601  * </p>
1602  *
1603  * <p>
1604  * <h2>Example:</h2>
1605 <pre class="brush:js">
1606 // abstract class that implements some algorithm, 
1607 // but leaves some details unspecified
1608 $class("AbstractBase", {
1609   // returns an array of numbers
1610   getData: $abstract(function() {}),
1611   
1612   // "protected" implementation detail of some algorithm.
1613   _shouldAddValue: $abstract(function(value) {}),
1614   
1615   // the algorithm that uses the abstract methods
1616   performSomeAlgorithmWithData: $final(function() {
1617     var data = this.getData();
1618     var result = 0;
1619     
1620     for (var i = 0; i < data.length; ++i) {
1621       if (this._shouldAddValue(data[i]) {
1622         result += data[i];
1623       }
1624     }
1625     
1626     return result;
1627   })
1628 });
1629 
1630 // class that implements the abstract methods
1631 $class("Implementation", {
1632   $extends: AbstractBase,
1633   
1634   $constructor: function(data) {
1635     this._data = data;
1636   },
1637   
1638   getData: function() {
1639     return this._data;
1640   },
1641   
1642   _shouldAddValue: function(value) {
1643     return value > 0;
1644   }
1645 });
1646 
1647 var abstractBase = new AbstractBase(); // ERROR!
1648 
1649 var impl = new Implementation([1, -5, 9, -10, 5]);
1650 alert(impl.performSomeAlgorithmWithData()); // alerts "15"
1651 </pre>
1652  * </p>
1653  *
1654  * @param {Function} method A function. The function itself is not actually used, but it must be provided.
1655  * This both allows for a sanity check that you aren not trying to create an abstract property (can't be done)
1656  * and provides a convenient place for you to declare/document the arguments.
1657  *
1658  * @return {Object} Something magical that, when assigned to a property of a {@link $class.descriptor}, causes
1659  * an abstract method to be created.
1660  */
1661 function $abstract(method) {
1662   return new $class._ModifiedProperty("abstract", method);
1663 }
1664 
1665 /**
1666  * <p>
1667  * Creates a static property or method in a class or interface. This is a property modifier for use within a 
1668  * {@link $class.descriptor} or {@link $interface.descriptor}. 
1669  * </p>
1670  * <p>
1671  * A static property/method is accessible as a property of the class or interface without having an instance.
1672  * Within static methods, the "this" keyword will refer to the class or interface to which the static method 
1673  * belongs. Static methods/properties are not inherited; you must access them on the exact class or interface 
1674  * in which they were defined. Note that static methods by definition cannot be made {@link $abstract} or 
1675  * {@link $final}.
1676  * </p>
1677  *
1678  * <p>
1679  * <h2>Example:</h2>
1680 <pre class="brush:js">
1681 $class("Sample", {
1682   $constructor: function(name, type) {
1683     this._name = name;
1684     this._type = type;
1685   },
1686   
1687   equalTo: function(other) {
1688     return other 
1689         && other instanceof Sample
1690         && other._name == this._name
1691         && other._type == this._type;
1692   },
1693   
1694   // static constants for indicating the "type"
1695   Type: $static({
1696     GOOD: 1,
1697     BETTER: 2,
1698     BEST: 3
1699   }),
1700   
1701   // static factory method
1702   createBestSample: $static(function(name) {
1703     // "this" in static methods refers to the class/constructor
1704     return new this(name, this.Type.BEST);
1705   })
1706 });
1707 
1708 var sample1 = new Sample("Bob", Sample.Type.BEST);
1709 var sample2 = Sample.createBestSample("Bob");
1710 
1711 alert(sample1.equalTo(sample2)); // alerts "true"
1712 </pre>
1713  * </p>
1714  *
1715  * @param {mixed} value Any value. May be a function.
1716  *
1717  * @return {Object} Something magical that, when assigned to a property of a {@link $class.descriptor} or 
1718  * {@link $interface.descriptor}, causes a static property to be created.
1719  */
1720 function $static(value) {
1721   return new $class._ModifiedProperty("static", value);
1722 }
1723 
1724 /**
1725  * <p>
1726  * Creates a final method in a class, or creates a final class. This is a property modifier for use within a 
1727  * {@link $class.descriptor}. 
1728  * </p>
1729  * <p>
1730  * A final method is not allowed to be overridden by descendent classes. The final modifier can also be applied
1731  * to the {@link $class.descriptor#$constructor} of a class to prevent the class from being overridden 
1732  * althogether. The final modifier may only be applied to non-{@link $abstract} and non-{@link $static} methods.
1733  * </p>
1734  * <p>
1735  *
1736  * <h2>Debug version errors:</h2>
1737  * <ul>
1738  *   <li>Attempt to extend a class whose constructor is final.</li>
1739  *   <li>Attempt to override an inherited final method.</li>
1740  * </ul>
1741  * </p>
1742  *
1743  * <p>
1744  * <h2>Example:</h2>
1745 <pre class="brush:js">
1746 // extend this class to inherit a unique ID
1747 $class("UniquelyIdentifiable", {
1748   $constructor: function() {
1749     this._id = "UniquelyIdentifiable_" + (UniquelyIdentifiable._idCounter++);
1750   },
1751   
1752   // If this method were ever overridden to do something different, it could
1753   // break the contract of this class (promises a unique ID). Making it final
1754   // keeps it completely within control of this class.
1755   getId: $final(function() {
1756     return this._id;
1757   }),
1758   
1759   _idCounter: $static(0)
1760 });
1761 </pre>
1762  * </p>
1763  *
1764  * @function
1765  *
1766  * @param {Function} method The implementation of the final method. 
1767  *
1768  * @return {Object} Something magical that, when assigned to a property of a {@link $class.descriptor), causes a final
1769  * method to be created.
1770  */
1771 function $final(method) {
1772   return new $class._ModifiedProperty("final", method);
1773 }
1774 
1775 //##############################################################################
1776 
1777 (function() {
1778   var nativeClassNames = [
1779     "Object",
1780     "Array",
1781     "String",
1782     "Number",
1783     "Boolean",
1784     "Function",
1785     "RegExp",
1786     "Date",
1787 
1788     "Error",
1789     "EvalError",
1790     "RangeError",
1791     "ReferenceError",
1792     "SyntaxError",
1793     "TypeError",
1794     "URIError"
1795   ];
1796 
1797   for (var i = 0, className; className = nativeClassNames[i]; ++i) {
1798     $class.adapt(this[className], className, true);
1799   }
1800 })();
1801 
1802 $class.adapt($namespace, "$namespace");
1803 $class.adapt($class,     "$class");
1804 $class.adapt($interface, "$interface");
1805 
1806 //##############################################################################
1807 
1808 /**
1809  * @name Undefined
1810  * @class
1811  * A dummy class used by various $class libray utility methods to represent the type of <em>undefined</em>
1812  * @see $class.typeOf
1813  * @see $class.instanceOf
1814  * @see $class.getClass
1815  */
1816 $class("Undefined", {
1817   Undefined: $final(function() {
1818     $class_library._error("Attempted instantiation of the Undefined class.");
1819   })
1820 });
1821 
1822 /**
1823  * @name Null
1824  * @class
1825  * A dummy class used by various $class libray utility methods to represent the type of <em>null</em>
1826  * @see $class.typeOf
1827  * @see $class.instanceOf
1828  * @see $class.getClass
1829  */
1830 $class("Null", {
1831   Null: $final(function() {
1832     $class_library._error("Attempted instantiation of the Null class.");
1833   })
1834 });
1835 
1836 //##############################################################################
1837 
1838 /**
1839  * @name $class.descriptor
1840  * @class
1841  * <p>
1842  * This is a fake class used to document the descriptor object that is passed to the {@link $class} 
1843  * function to define a class. The documented properties are handled specially as described by each property.
1844  * All possible property names beginning with a dollar sign ($), or an underscore and dollar sign (_$) are to 
1845  * be considered reserved for use by the $class library. Anything else is fair game for defining properties 
1846  * and methods in a class.
1847  * </p>
1848  *
1849  * <p>
1850  * Unless documented otherwise, all properties in the descriptor are simply copied to the prototype of the 
1851  * new class, making them instance properties or instance methods. It is recommended that you avoid creating 
1852  * instance properties that are not methods. Instance properties of the class should generally be defined 
1853  * and initialized in the constructor to avoid non-obvious bugs that can arise from multiple instances 
1854  * unintentionally sharing a reference to an array or object through a prototype property.
1855  * </p>
1856  *
1857  * <p>
1858  * <h2>Property Modifiers</h2>
1859  * The following modifiers can be applied to properties in the descriptor. See the documentation for each 
1860  * modifier for details and examples.
1861  * <ul>
1862  *   <li>{@link $static} - create a static property or method.</li>
1863  *   <li>{@link $final} - prevent a method from being overridden (can also be applied to the {@link #$constructor}).</li>
1864  *   <li>{@link $abstract} - create an abstract method.</li>
1865  * </ul>
1866  * You may have noticed that there is no "private" modifier. I know that there's techniques for making 
1867  * "private fields" that truly cannot be accessed externally, but I don't believe the benefit outweighs the cost
1868  * in overhead and reduced maintainability of the code (it's hard to recognize which identifiers are actually 
1869  * private fields vs local or global variables). I prefer the simplicity of a leading underscore (_) for the names
1870  * of private fields and methods.
1871  * </p>
1872  *
1873  * <p>
1874  * <a name="$base"></a>
1875  * <h2>this.$base</h2>
1876  * In any non-static method (including the constructor), a special property named "$base" can be used to call
1877  * the overridden implementation of the same method. The overhead of supporting this special property 
1878  * is only added if the method contains a reference to this.$base (as determined by a simple regular expression). 
1879 <pre class="brush:js">
1880 $class("Person", {
1881   $constructor: function(name) {
1882     this._name = name;
1883   },
1884   
1885   getName: function() {
1886     return this._name;
1887   }
1888 });
1889 
1890 $class("Officer", {
1891   $extends: Person,
1892   
1893   $constructor: function(name, rank) {
1894     // call Person's constructor implementation
1895     this.$base(name);
1896     this._rank = rank;
1897   },
1898   
1899   getName: function() {
1900     // add the officer's rank to the name
1901     return this._rank + " " + this.$base();
1902   }
1903 });
1904 
1905 var officer = new Officer("Coltraine", "Sheriff");
1906 alert(officer.getName()); // alerts "Sheriff Coltraine"
1907 </pre>
1908  * </p>
1909  */
1910 $class_library._$class_descriptor_docs = 
1911 /**
1912  * @lends $class.descriptor.prototype
1913  */
1914 {
1915   /**
1916    * <p>
1917    * A function that will be used to implement the constructor of the class. A constructor is not required. If
1918    * not specified, a default constructor will be created. Default constructors will automatically call the 
1919    * parent class's constructor with all the arguments that were passed in. Use the special 
1920    * <a href="#$base">this.$base</a> property to 
1921    * call the parent class's constructor (a.k.a., initializing the parent class) with specific arguments. If a 
1922    * constructor is provided, but there is no usage of this.$base, the parent class's constructor will be 
1923    * automatically called before your constructor implementation (with all the same arguments).
1924    * </p>
1925    *
1926    * <p>
1927    * The constructor may be modified with the {@link $final} modifier to make the entire class final (prevents
1928    * other classes from extending this class).
1929    * </p>   
1930    *
1931    * <p>
1932    * The constructor can also be provided as a property whose name is the same as the class's name.
1933    * </p>   
1934    *
1935    * <p>
1936    * <h2>Debug version warnings:</h2>
1937    * <ul>
1938    *   <li>No constructor specified; using default constructor.</li>
1939    * </ul>
1940    * </p>
1941    *
1942    * <p>
1943    * <h2>Debug version errors:</h2>
1944    * <ul>
1945    *   <li>Constructor value is not a function.</li>
1946    * </ul>
1947    * </p>
1948    *
1949    * <p>
1950    * <h2>Optimized trivial constructors:</h2>
1951    * If there nothing in the body of the constructor function (no comments; only whitespace), or if no 
1952    * constructor is provided, then it is considered to be a trivial constructor. In the non-debug version of 
1953    * the $class library, trivial constructors are skipped when instantiating classes with a chain of 
1954    * inheritance. For example, let's say there is an inheritance chain of classes: A <- B <- C <- D <- E 
1955    * (A is the base class in this chain). If A, B and D all have trivial constructors, then the instantiation 
1956    * of B will simply execute a single empty function. Instantiating C will execute only C's constructor.
1957    * Instantiating D will execute a wrapper function that simply call's C's constructor. Instantiating E will
1958    * execute E's constructor, then skip right to C's constructor (even if E's constructor explicitly calls 
1959    * <a href="#$base">this.$base</a>).
1960    * </p>
1961    *
1962    * <p>
1963    * <h2>Example:</h2>
1964 <pre class="brush:js">
1965 $namespace("Shapes");
1966 
1967 $class("Shapes.Rectangle", {
1968   // this is a constructor
1969   $constructor: function(width, height) {
1970     this._width = width;
1971     this._height = height;
1972   }
1973 });
1974 
1975 $class("Shapes.Square", {
1976   $extends: Rectangle,
1977 
1978   // this is a constructor too
1979   Square: function(size) {
1980     // Call Square's constructor implementation
1981     this.$base(size, size);
1982   }
1983 });
1984 </pre>
1985    * </p>
1986    *
1987    * @type Function
1988    */
1989   $constructor: null,
1990   
1991   /**
1992    * <p>
1993    * A class to be inherited by this class. Instances of this class will be considered to be instances of the 
1994    * specified parent class by both the JavaScript "instanceof" keyword, and {@link $class#instanceOf}. All
1995    * instance methods and properties will be inherited. This class will be considered to implement all 
1996    * {@link $interface}s that are implemented by the parent class. 
1997    * </p>
1998    *
1999    * <p>
2000    * See {@link #$constructor} for details about initializing the parent class.
2001    * </p>
2002    *
2003    * <p>
2004    * <h2>Debug version errors:</h2>
2005    * <ul>
2006    *   <li>$extends is specified, but the value is null/undefined. This usually indicates that you attempted
2007    *       to extend a class and forgot to include the JS file that defines that class, or maybe you misspelled
2008    *       the class name.</li>
2009    *   <li>Attempt to extend something that is not a Function.</li>
2010    *   <li>Attempt to extend a class whose {@link #$constructor} is {@link $final}.</li>
2011    *   <li>Attempt of a non-multiton class to extend a multiton ({@link $class.descriptor#$multiton}).</li>
2012    *   <li>Attempt of a non-singleton class to extend a singleton ({@link $class.descriptor#$singleton}).</li>
2013    * </ul>
2014    * </p>
2015    *
2016    * <p>
2017    * <h2>Debug version warnings:</h2>
2018    * <ul>
2019    *   <li>The class being extended is being automatically adapted into the $class framework with a generated
2020    *       name (see {@link $class.adapt})</li>
2021    * </ul>
2022    * </p>
2023    *
2024    * <p>
2025    * <h2>Example:</h2>
2026 <pre class="brush:js">
2027 $class("Rectangle", {
2028   // this is a constructor
2029   $constructor: function(width, height) {
2030     this._width = width;
2031     this._height = height;
2032   },
2033   
2034   getArea: function() {
2035     return this._width * this.height;
2036   }
2037 });
2038 
2039 $class("Square", {
2040   $extends: Rectangle,
2041 
2042   // this is a constructor too
2043   Square: function(size) {
2044     // Call Square's constructor implementation
2045     this.$base(size, size);
2046   }
2047 });
2048 
2049 var square = new Square(10);
2050 
2051 alert(square instanceof Square); // alerts "true"
2052 alert(square instanceof Rectangle); // alerts "true"
2053 alert(square.getArea()); // alerts "100"
2054 </pre>
2055    * </p>
2056    *
2057    * @type Function
2058    *
2059    * @see $class#instanceOf
2060    */
2061   $extends: null,
2062   
2063   /**
2064    * <p>
2065    * One or more {@link $interface}s that are implemented by this class. All methods of all interfaces must be
2066    * present in this class. Inherited methods and {@link $abstract} methods both satisfy this requirement.
2067    * </p>
2068    *
2069    * <p>
2070    * <h2>Debug version errors:</h2>
2071    * <ul>
2072    *   <li>Interface method not implemented in the class. The error message will list all methods not 
2073    *       implemented.</li>
2074    * </ul>
2075    * </p>
2076    *
2077    * <p>
2078    * <h2>Example:</h2>
2079 <pre class="brush:js">
2080 $interface("Identifiable", {
2081   getId: function() {}
2082 });
2083 
2084 $interface("Named", {
2085   getName: function() {}
2086 });
2087 
2088 $class("Person", {
2089   $implements: [Identifiable, Named],
2090   
2091   $constructor: function(governmentId, name) {
2092     this._governmentId = governmentId;
2093     this._name = name;
2094   },
2095   
2096   getId: function() {
2097     return this._governemtnId;
2098   },
2099   
2100   getName: function() {
2101     return this._name;
2102   }
2103 });
2104 </pre>
2105    * </p>
2106    *
2107    * @type ($interface|$interface[])
2108    *
2109    * @see $class#implementsInterface
2110    * @see $class#implementionOf
2111    * @see $class#instanceOf
2112    */
2113   $implements: null,
2114   
2115   /**
2116    * <p>
2117    * A static initializer function that is executed immediately after the class is created. This can be used 
2118    * to perform complex initialization of {@link $static} properties. Like static methods, the static
2119    * initializer is executed within the context of the class/constructor.
2120    * </p>
2121    *
2122    * <p>
2123    * <h2>Example:</h2>
2124 <pre class="brush:js">
2125 $class("Example", {
2126   ValuesMap: $static({
2127     ZERO: 0,
2128     ONE: 1,
2129     TWO: 2,
2130     THREE: 3
2131   }),
2132   
2133   // initialized in the static initializer
2134   ValuesReverseMap: $static({}),
2135   
2136   $static: function() {
2137     for (var i in this.ValuesMap) {
2138       this.ValuesReverseMap[this.ValuesMap[i]] = i;
2139     }
2140   }
2141 });
2142 
2143 // static initializer has already been executed by this point.
2144 // alerts "true"
2145 alert(Example.ValuesReverseMap[Example.ValuesMap["TWO"]] == "TWO");
2146 </pre>
2147    * </p>
2148    *
2149    * @type Function
2150    */
2151   $static: null,
2152   
2153   /**
2154    * <p>
2155    * By default, every class created by {@link $class} will have its own toString implementation that returns a 
2156    * string in the form "[object _name_]", where _name_ is the full name of the class. This can be useful for 
2157    * debugging. toString can be overridden with a custom implementation in any class.
2158    * </p>
2159    *
2160    * @type Function
2161    */
2162   toString: null,
2163   
2164   /**
2165    * <p>
2166    * Configures a class as a singleton. A singleton cannot be directly instantiated. A static "getInstance" method
2167    * is automatically created that will take care of instantiating the class the first time and returning the same
2168    * instance from all subsequent calls.
2169    * </p>
2170    *
2171    * <p>
2172    * The value of this property can either be an anonymous {@link $class.descriptor.singleton_config} object, or 
2173    * simply a boolean "true" if the defaults of the config object are acceptable.
2174    * </p>
2175    *
2176    * <p>
2177    * The advantages of creating a singleton this way (as opposed to simply creating a global named object with some
2178    * methods and properties) is that it defers initialization until the first use in code, and it can extend another
2179    * class, implement interfaces, etc.
2180    * </p>
2181    *
2182    * <p>
2183    * A singleton can extend any non-{@link $final} class that is not a multiton ({@link $class.descriptor#$multiton}). 
2184    * Yes, a singleton can extend another singleton. Instances are not shared between parent and child singleton, so by 
2185    * extending singleton, you will technically end up with two equivalent instances of the parent class (one of 
2186    * them actually being an instance of the child class). Non-singleton classes cannot extend a singleton.
2187    * What does it mean for a singleton to extend another singleton? I dunno; you tell me. I couldn't absolutely 
2188    * convince myself to disallow it, so here it is.
2189    * </p>
2190    *
2191    * <p>
2192    * <h2>Warning:</h2>
2193    * If you currently only need one instance and you're just being lazy and designing your class as a singleton so
2194    * that you can call getInstance() in multiple places instead of passing a reference around, you should really 
2195    * just spend the little bit of extra time to instantiate your class in one place and pass it to the constructors
2196    * of the various classes that need to reference it. You'll thank me some day when you need to reuse your code 
2197    * some day in a way such that your singleton needs to be dynamically reconfigured or you actually find that you
2198    * really do need multiple simultaneous instances with different configurations. It's much easier, cleaner and 
2199    * less error-prone to reinstantiate objects with new data than it is to hack up a singleton to reconfigure 
2200    * itself.
2201    * </p>
2202    *
2203    * <p>
2204    * <h2>Example:</h2>
2205 <pre class="brush:js">
2206 $class("Example", {
2207   $singleton: true,
2208   
2209   $constructor: function() {
2210     this._value = 0;
2211   },
2212   
2213   getValue: function() {
2214     return this._value;
2215   },
2216   
2217   incrementValue: function() {
2218     ++this._value;
2219   }
2220 });
2221 
2222 var example1 = Example.getInstance();
2223 var example2 = Example.getInstance();
2224 
2225 alert(example1 == example2); // alerts "true"
2226 alert(example1.getValue()); // alerts "0"
2227 alert(example2.getValue()); // alerts "0"
2228 
2229 example1.incrementValue();
2230 alert(example2.getValue()); // alerts "1"
2231 </pre>
2232    * </p>
2233    *
2234    * @type ($class.descriptor.singleton_config|Boolean)
2235    */
2236   $singleton: null,
2237   
2238   /**
2239    * <p>
2240    * Configures a class as a multiton. A multiton cannot be directly instantiated. A static "getInstance" method
2241    * is automatically created that will take care of instantiating the class the first time with a given set of and
2242    * arguments and returning the same instance from all subsequent calls with the same set of arguments.
2243    * </p>
2244    *
2245    * <p>
2246    * The value of this property can either be an anonymous {@link $class.descriptor.multiton_config} object, or 
2247    * simply a boolean "true" if the defaults of the config object are acceptable.
2248    * </p>
2249    *
2250    * <p>
2251    * Multitons are generally good for classes that are expensive to instantiate and if only a relatively small 
2252    * number of instances will each be referenced multiple times, but you want to avoid the hassle of maintaining 
2253    * references to instances. This is a very simple caching system that can provide performance improvements, but 
2254    * does not allow for any control over the cache, such as enforcing a limit to the cache.
2255    * </p>
2256    *
2257    * <p>
2258    * A multiton can extend any non-{@link $final} class that is not a singleton ({@link $class.descriptor#$singleton}).
2259    * Yes, a multiton can extend another multiton. Instances are not shared between parent and child multitons, so by 
2260    * extending multitons, you can technically end up with two equivalent instances of the parent class (one of
2261    * them actually being an instance of the child class). Non-multiton classes cannot extend a multiton.
2262    * What does it mean for a multiton to extend another multiton? I dunno; you tell me. I couldn't absolutely 
2263    * convince myself to disallow it, so here it is.
2264    * </p>
2265    *
2266    * <p>
2267    * <h2>Warning:</h2>
2268    * By default, the cache key is built very naively. If there is any way that different parameter values could
2269    * produce identical instances of your class, then you must provide your own cache key algorithm. This problem
2270    * is illustrated in the example. See {@link $class.descriptor.multiton_config#createCacheKey} for details about
2271    * providing your own cache key algorithm.
2272    * </p>
2273    * 
2274    * <p>
2275    * <h2>Example:</h2>
2276 <pre class="brush:js">
2277 $class("Example", {
2278   $multiton: true,
2279   
2280   // name defaults to "John Doe" if empty or null
2281   $constructor: function(name) {
2282     this._name = name || "John Doe";
2283   },
2284   
2285   getName() {
2286     return this._name;
2287   }
2288 });
2289 
2290 var example1 = Example.getInstance("John Doe");
2291 var example2 = Example.getInstance("John Doe");
2292 
2293 // same instance if instantiated with the same arguments
2294 alert(example1 == example2) // alerts "true"
2295 
2296 // instantiate with different arguments...
2297 var example3 = Example.getInstance(null);
2298 
2299 // different instance
2300 alert(example2 == example3) // alerts "false"
2301 // ... but the same name
2302 alert(example2.getName() == example3.getName()) // alerts "false"
2303 </pre>
2304    * </p>
2305    *
2306    * @type ($class.descriptor.multiton_config|Boolean)
2307    */
2308   $multiton: null
2309 };
2310 
2311 /**
2312  * @name $class.descriptor.singleton_config
2313  * @class
2314  * <p>
2315  * This is a fake class to document the configuration object for use with {@link $class.descriptor#$singleton}
2316  * to setup a class as a singleton. If the defaults are acceptable, you can simply provide a value of 
2317  * <em>true</em> instead of a singleton config object.
2318  * </p>
2319  */
2320 $class_library._$singleton_config_docs = 
2321 /**
2322  * @lends $class.descriptor.singleton_config.prototype
2323  */
2324 {
2325   /**
2326    * <p>
2327    * A function that is used to create the singleton instance. This function receives no arguments and is 
2328    * expected to return an instance of the class. The function is called within the context of the 
2329    * class/constructor. Defaults to a function that simply instantiates the class with no constructor arguments.
2330    * </p>
2331    *
2332    * <p>
2333    * This property is useful for when you want to have a singleton, but it needs be instantiated with 
2334    * "dynamic static data"; data that is determined by the server so that it cannot be hard-coded in the JavaScript, 
2335    * but the data never changes during the lifetime of the script, so it is static as far as the script is 
2336    * concerned.
2337    * </p>
2338    *
2339    * <p>
2340    * Defaults to a function that simply instantiates the class with the same arguments.
2341    * </p>
2342    *
2343    * <p>
2344    * <h2>Warning:</h2>
2345    * If you think you want to do something like this, chances are that you really shouldn't be creating a singleton.
2346    * This pattern of initializing a singleton with "dynamic static data" should only be used if the purpose of the 
2347    * class inherently makes the design require that there never be more than one instance, because multiple 
2348    * instances would catastrophically interfere with each other or other data. See also the warning about 
2349    * {@link $class.descriptor#$singleton}.
2350    * </p>
2351    *
2352    * <p>
2353    * <h2>Example:</h2>
2354 <pre class="brush:js">
2355 $class("Example", {
2356   $singleton: {
2357     createInstance: function() {
2358       // A default value allows the code to not depend on an externally 
2359       // defined value 
2360       var paramValue = this.DEFAULT_PARAM_VALUE;
2361       
2362       // If a global variable "EXAMPLE_PARAM_VALUE" exists, use its value.
2363       // The value of this variable could have been rendered by server 
2364       // code (PHP, JSP, etc). This allows default behavior/configuration
2365       // to be overridden if desired.
2366       if (typeof EXAMPLE_PARAM_VALUE != "undefined") {
2367         paramValue = EXAMPLE_PARAM_VALUE;
2368       }      
2369       
2370       return new this(paramValue);
2371     },
2372   },
2373   
2374   $constructor: function(param) {
2375     this._param = param;
2376   },
2377   
2378   getParam: function() {
2379     return this._param;
2380   },
2381   
2382   DEFAULT_PARAM_VALUE: $static(10)
2383 });
2384 
2385 var EXAMPLE_PARAM_VALUE = 5;
2386 alert(Example.getInstance().getParam()); // alerts "5"
2387 
2388 EXAMPLE_PARAM_VALUE = 20;
2389 alert(Example.getInstance().getParam()); // still alerts "5"
2390 </pre>
2391    * </p>
2392    *
2393    * @type Function
2394    */
2395   createInstance: null
2396 };
2397 
2398 /**
2399  * @name $class.descriptor.multiton_config
2400  * @class
2401  * <p>
2402  * This is a fake class to document the configuration object for use with {@link $class.descriptor#$multiton}
2403  * to setup a class as a multiton. If the defaults are acceptable, you can simply provide a value of 
2404  * <em>true</em> instead of a multiton config object.
2405  * </p>
2406  */
2407 $class_library._$multiton_config_docs = 
2408 /**
2409  * @lends $class.descriptor.multiton_config.prototype
2410  */
2411 {
2412   /**
2413    * <p>
2414    * A function that is used to create each multiton instance. This function receives all arguments that are 
2415    * passed to the class's static getInstance method and is expected to return an instance of the class. The 
2416    * function is called within the context of the class/constructor. Defaults to a function that simply 
2417    * instantiates the class with the same arguments that were passed to getInstance().
2418    * </p>
2419    *
2420    * <p>
2421    * I'm having a hard time coming up with a legitemate use for this property, but it seemed like it should be 
2422    * supported to maintain consistency with {@link $class.descriptor.singleton_config}. Good luck :)
2423    * </p>
2424    *
2425    * @type Function
2426    */
2427   createInstance: null,
2428   
2429   /**
2430    * <p>
2431    * A function that is used to create a cache key for looking up cached multiton instances. This function 
2432    * receives all arguments that are passed to the class's static getInstance method and is expected to return
2433    * a String that uniquely identifies the combination of arguments. The arguments should be "normalized", such 
2434    * that if two different sets of arguments would be interpretted the same and result in equivalent instances,
2435    * an identical cache key should be generated for those two different sets of arguments.  
2436    * </p>
2437    *
2438    * <p>
2439    * Defaults to a function that simply converts all arguments to Strings and joins them together with pipes (|).
2440    * </p>
2441    *
2442    * <p>
2443    * <h2>Example:</h2>
2444 <pre class="brush:js">
2445 $class("Example", {
2446   $multiton: {
2447     createCacheKey: function(name) {
2448       // the cache key must account for any kind of 
2449       // defaulting/processing of params in the constructor
2450       return name || "John Doe";
2451     }
2452   },
2453   
2454   // name defaults to "John Doe" if empty or null
2455   $constructor: function(name) {
2456     this._name = name || "John Doe";
2457   },
2458   
2459   getName() {
2460     return this._name;
2461   }
2462 });
2463 
2464 var example1 = Example.getInstance(null);
2465 var example2 = Example.getInstance("John Doe");
2466 
2467 // same name
2468 alert(example1.getName() == example2.getName()) // alerts "true"
2469 // same instance
2470 alert(example1 == example2) // alerts "true"
2471 </pre>
2472    * </p>
2473    *
2474    * @type Function
2475    */
2476   createCacheKey: null
2477 };
2478 
2479 /**
2480  * @name $interface.descriptor
2481  * @class
2482  * <p>
2483  * This is a fake class used to document the descriptor object that is passed to the {@link $interface} 
2484  * function to define an interface. The documented properties are handled specially as described by each property.
2485  * All possible property names beginning with a dollar sign ($), or an underscore and dollar sign (_$) are to 
2486  * be considered reserved for use by the $class library. Anything else is fair game for defining properties 
2487  * and methods in an interface.
2488  * </p>
2489  *
2490  * <p>
2491  * Unless documented otherwise, all properties in the descriptor are expected to describe interface methods. The 
2492  * value of these properties must be a function, but its implementation will not be used, so don't bother writing
2493  * code in the body of the function. Providing a function value for these properties gives you a good place to
2494  * define and document params and return values. It also allows the debug version of the $class library to yell at
2495  * you if you try to create a non-static non-method property on an interface.
2496  * </p>
2497  *
2498  * <p>
2499  * <h2>Property Modifiers</h2>
2500  * The following modifiers can be applied to properties in the descriptor. See the documentation for each 
2501  * modifier for details and examples.
2502  * <ul>
2503  *   <li>{@link $static} - create a static property or method.</li>
2504  * </ul>
2505  * </p>
2506  */
2507 $class_library._$interface_descriptor_docs = 
2508 /**
2509  * @lends $interface.descriptor.prototype
2510  */
2511 {
2512   /**
2513    * <p>
2514    * One or more interfaces to be inherited by this interface. Implementations of this interface will be considered
2515    * to be implementations of all inherited interfaces. All interface methods will be inherited, meaning that  
2516    * implementations of this interface must implement all methods of all inherited interfaces in addition to any
2517    * methods defined by this interface.
2518    * </p>
2519    *
2520    * <p>
2521    * <h2>Debug version errors:</h2>
2522    * <ul>
2523    *   <li>$extends is specified, but one of the values is null/undefined. This usually indicates that you attempted
2524    *       to extend an interface and forgot to include the JS file that defines that interface, or maybe you 
2525    *       misspelled the interface name.</li>
2526    *   <li>Attempt to extend something that is not an $interface.</li>
2527    * </ul>
2528    * </p>
2529    *
2530    * @type $interface|$interface[]
2531    */
2532   $extends: null
2533 };
2534