1 /*global window, document*/
  2 /*jslint bitwise: true, unparam: true, regexp: true*/
  3 
  4 (function (window, document) {
  5     'use strict';
  6     var BytePushers;
  7 
  8     if (window.BytePushers !== undefined && window.BytePushers !== null) {
  9         BytePushers = window.BytePushers;
 10     } else {
 11         window.BytePushers = {};
 12         BytePushers = window.BytePushers;
 13     }
 14     /****************************************************************************************************
 15     * BEGIN Array Extensions */
 16     if (!Array.prototype.every) {
 17         Array.prototype.every = function (fun, funParameter) {
 18             var t = Object.create(this),
 19                 len = t.length >>> 0,
 20                 i;
 21 
 22             if (this === null) {
 23                 throw new TypeError();
 24             }
 25 
 26             if (typeof fun !== "function") {
 27                 throw new TypeError();
 28             }
 29 
 30             for (i = 0; i < len; i = i + 1) {
 31                 if (t.hasOwnProperty(i) && !fun.call(funParameter, t[i], i, t)) {
 32                     return false;
 33                 }
 34             }
 35 
 36             return true;
 37         };
 38     }
 39 
 40     // Production steps of ECMA-262, Edition 5, 15.4.4.18
 41     // Reference: http://es5.github.com/#x15.4.4.18
 42     if (!Array.prototype.forEach) {
 43 
 44         Array.prototype.forEach = function forEach(callback, thisArg) {
 45 
 46             var T, k, O, len, obj = {}, kValue;
 47 
 48             if (this === null) {
 49                 throw new TypeError("this is null or not defined");
 50             }
 51 
 52             // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
 53             O = Object.create(this);
 54 
 55             // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
 56             // 3. Let len be ToUint32(lenValue).
 57             len = O.length >>> 0; // Hack to convert O.length to a UInt32
 58 
 59             // 4. If IsCallable(callback) is false, throw a TypeError exception.
 60             // See: http://es5.github.com/#x9.11
 61             if (obj.toString.call(callback) !== "[object Function]") {
 62                 throw new TypeError(callback + " is not a function");
 63             }
 64 
 65             // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
 66             if (thisArg) {
 67                 T = thisArg;
 68             }
 69 
 70             // 6. Let k be 0
 71             k = 0;
 72 
 73             // 7. Repeat, while k < len
 74             while (k < len) {
 75                 // a. Let Pk be ToString(k).
 76                 //   This is implicit for LHS operands of the in operator
 77                 // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
 78                 //   This step can be combined with c
 79                 // c. If kPresent is true, then
 80                 if (Object.prototype.hasOwnProperty.call(O, k)) {
 81 
 82                     // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
 83                     kValue = O[k];
 84 
 85                     // ii. Call the Call internal method of callback with T as the this value and
 86                     // argument list containing kValue, k, and O.
 87                     callback.call(T, kValue, k, O);
 88                 }
 89                 // d. Increase k by 1.
 90                 k = k + 1;
 91             }
 92             // 8. return undefined
 93         };
 94     }
 95 
 96     if (!Array.prototype.some) {
 97         Array.prototype.some = function (fun, functionParameter) {
 98             var t = Object.create(this),
 99                 len = t.length >>> 0,
100                 i;
101 
102             if (this === null) {
103                 throw new TypeError();
104             }
105 
106             if (typeof fun !== "function") {
107                 throw new TypeError();
108             }
109 
110             for (i = 0; i < len; i = i + 1) {
111                 if (t.hasOwnProperty(i) && fun.call(functionParameter, t[i], i, t)) {
112                     return true;
113                 }
114             }
115 
116             return false;
117         };
118     }
119 
120     if (!Array.prototype.isArray) {
121         Array.prototype.isArray = function (arg) {
122             var targetArray = (arg === true) ? arg : this;
123             return Object.prototype.toString.call(targetArray) === "[object Array]";
124         };
125     }
126 
127     /* END Array Extensions *
128      ****************************************************************************************************/
129 
130     /****************************************************************************************************
131      * BEGIN Date Extensions */
132     /**
133      * <p>Function that is used to determine if two dates objects have the same date.</p>
134      * @function
135      * @param {@link Date} The date to evaluate against this object.
136      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a> True if the date passed in is equal the date object; otherwise return false.
137      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
138      */
139     Date.prototype.isDateEqualTo = function (date) {
140         if (this.getFullYear() === date.getFullYear()) {
141             if (this.getMonth() === date.getMonth()) {
142                 if (this.getDate() === date.getDate()) {
143                     return true;
144                 }
145             }
146         }
147         return false;
148     };
149 
150     /**
151      * <p>Function that is used to determine if two dates objects have the same date and time.</p>
152      * @function
153      * @param {@link Date} The date to evaluate against this object.
154      * @return {@link <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a>} True if the date passed in is equal the date object; otherwise return false.
155      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
156      */
157     Date.prototype.isDateEqualToDateAndTime = function (date) {
158         if (this.getFullYear() === date.getFullYear()) {
159             if (this.getMonth() === date.getMonth()) {
160                 if (this.getDate() === date.getDate()) {
161                     if (this.getHours() === date.getHours()) {
162                         if (this.getMinutes() === date.getMinutes()) {
163                             return true;
164                         }
165                     }
166                 }
167             }
168         }
169         return false;
170     };
171 
172     /**
173      * <p>Function that is used to determine a date is the day after another date.</p>
174      * @function
175      * @param {@link Date} The date to evaluate against this object.
176      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a> True if the date is the day after the original date; otherwise return false.
177      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
178      */
179     Date.prototype.isDateEqualToTomorrow = function (date) {
180         if (this.getFullYear() === date.getFullYear()) {
181             if (this.getMonth() === date.getMonth()) {
182                 if (this.getDate() + 1 === date.getDate()) {
183                     return true;
184                 }
185             } else if (this.getMonth() + 1 === date.getMonth()) {
186                 if (this.isLastDayInMonth() && date.getDate() === 1) {
187                     return true;
188                 }
189             }
190         } else if (this.getFullYear() + 1 === date.getFullYear()) {
191             if (this.getMonth() === 11 && date.getMonth() === 0) {
192                 if (this.getDate() === 31 && date.getDate() === 1) {
193                     return true;
194                 }
195             }
196         }
197         return false;
198     };
199 
200     /**
201      * <p>Function that is used to determine a date is the day before another date.</p>
202      * @function
203      * @param {@link Date} The date to evaluate against this object.
204      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a> True if the date is the day before the original date; otherwise return false.
205      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
206      */
207     Date.prototype.isDateEqualToYesterday = function (date) {
208         if (this.getFullYear() === date.getFullYear()) {
209             if (this.getMonth() === date.getMonth()) {
210                 if (this.getDate() - 1 === date.getDate()) {
211                     return true;
212                 }
213             } else if (this.getMonth() === date.getMonth() + 1) {
214                 if (this.getDate() === 1 && date.isLastDayInMonth()) {
215                     return true;
216                 }
217             }
218         } else if (this.getFullYear() - 1 === date.getFullYear()) {
219             if (this.getMonth() === 0 && date.getMonth() === 11) {
220                 if (this.getDate() === 1 && date.getDate() === 31) {
221                     return true;
222                 }
223             }
224         }
225         return false;
226     };
227 
228     /**
229      * <p>Tells you whether it is the last day in a month or not.</p>
230      * @private
231      * @returns <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a> True if it is the last day of the month, otherwise false.
232      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
233      */
234     Date.prototype.isLastDayInMonth = function () {
235         var lastDayInMonth = this.getCurrentMonthTotalDays();
236         if (this.getDate() === lastDayInMonth) {
237             return true;
238         }
239         return false;
240     };
241 
242     /**
243      * <p>Function that is used to get calendar total calendar days of the previous month.</p>
244      * @function
245      * @returns <a href="http://www.w3schools.com/jsref/jsref_obj_number.asp">Number</a> The total days in the previous month.
246      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
247      */
248     Date.prototype.getPreviousMonthTotalDays = function () {
249         if (this.getMonth() === 0) {
250             return Date.monthNames[11].getTotalDays(this.getFullYear());
251         }
252 
253         return Date.monthNames[this.getMonth() - 1].getTotalDays(this.getFullYear());
254     };
255 
256     /**
257      * <p>Function that is used to get the total calendar days of the next month.</p>
258      * @function
259      * @returns <a href="http://www.w3schools.com/jsref/jsref_obj_number.asp">Number</a> The total days in the next month.
260      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
261      */
262     Date.prototype.getNextMonthTotalDays = function () {
263         if (this.getMonth() === 11) {
264             return Date.monthNames[0].getTotalDays(this.getFullYear());
265         }
266 
267         return Date.monthNames[this.getMonth() + 1].getTotalDays(this.getFullYear());
268     };
269 
270     /**
271      * <p>Function that is used to get the total calendar days of the next month.</p>
272      * @function
273      * @returns <a href="http://www.w3schools.com/jsref/jsref_obj_number.asp">Number</a> The total days in the next month.
274      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
275      */
276     Date.prototype.getCurrentMonthTotalDays = function () {
277         if (this.getMonth() === 11) {
278             return Date.monthNames[0].getTotalDays(this.getFullYear());
279         }
280 
281         return Date.monthNames[this.getMonth()].getTotalDays(this.getFullYear());
282     };
283 
284     /**
285      * <p>Adds time to a date object.</p>
286      * @param <a href="http://www.w3schools.com/jsref/jsref_obj_number.asp">Number</a> time Represents the time you want to add to the date.
287      *
288      * @returns {String} A new Date object with the specified time added.
289      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
290      */
291     Date.prototype.addTime = function (time) {
292         var newDate = new Date(),
293             wholeNumber = (time > 0) ? Math.floor(time) : Math.ceil(time),
294             fraction = ((time - wholeNumber).toFixed(2) * 100),
295             hourInMilliseconds = 1000 * 60 * 60 * wholeNumber,
296             minutesInMilliseconds = 1000 * 60 * fraction;
297 
298         newDate.setTime(this.getTime());
299         newDate.setTime(newDate.getTime() + hourInMilliseconds);
300         newDate.setTime(newDate.getTime() + minutesInMilliseconds);
301 
302         return newDate;
303     };
304     /**
305      * <p>Static function that tells you whether a date is the last day in a month or not.</p>
306      * @private
307      * @static
308      * @param <a href="http://www.w3schools.com/jsref/jsref_obj_date.asp">Number</a> time Represents the time you want to add to the date.
309      * @returns <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a> True if it is the last day of the month, otherwise false.
310      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
311      */
312     Date.isLastDayInMonth = function (date) {
313         var lastDayInMonth = date.getCurrentMonthTotalDays();
314         if (date.getDate() === lastDayInMonth) {
315             return true;
316         }
317         return false;
318     };
319 
320     /**
321      * <p>Static function that gets month name.</p>
322      * @private
323      * @static
324      * @param <a href="http://www.w3schools.com/jsref/jsref_obj_number.asp">Number</a> index Represents the position of the month in a month array.
325      * @param <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a> useAbbr An optional boolean flag that governs whether the
326      * full name of the month is returned or its abbreviation.
327      * @returns {String} The name of the month.
328      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
329      */
330     Date.getMonthName = function (index, getAbbr) {
331         if (getAbbr) {
332             return this.monthNames[index].abbr;
333         }
334 
335         return this.monthNames[index].name;
336     };
337 
338     /**
339      * <p>Static field for the list of month.</p>
340      * @static
341      * @field
342      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
343      */
344     Date.monthNames = [
345         {"name": "January", "abbr": "Jan", "getTotalDays": function () { return 31; } },
346         {"name": "February", "abbr": "Feb", "getTotalDays": function (year) {
347             if (year) {
348                 return (year % 4 === 0) ? 29 : 28;
349             }
350 
351             throw ("Expected parameter(Year) is not defined.");
352         }},
353         {"name": "March", "abbr": "Mar", "getTotalDays": function () { return 31; }},
354         {"name": "April", "abbr": "Apr", "getTotalDays": function () { return 30; }},
355         {"name": "May", "abbr": "May", "getTotalDays": function () { return 31; }},
356         {"name": "June", "abbr": "Jun", "getTotalDays": function () { return 30; }},
357         {"name": "July", "abbr": "Jul", "getTotalDays": function () { return 31; }},
358         {"name": "August", "abbr": "Aug", "getTotalDays": function () { return 31; }},
359         {"name": "September", "abbr": "Sep", "getTotalDays": function () { return 30; }},
360         {"name": "October", "abbr": "Oct", "getTotalDays": function () { return 31; }},
361         {"name": "November", "abbr": "Nov", "getTotalDays": function () { return 30; }},
362         {"name": "December", "abbr": "Dec", "getTotalDays": function () { return 31; }}
363     ];
364     /* END Date Extensions *
365      ****************************************************************************************************/
366 
367     /****************************************************************************************************
368      * BEGIN Object Extensions */
369     /**
370      * <p>Static function that tells you whether an object is an array or not.</p>
371      * @static
372      * @param <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures">Object of some type</a> The object that will be tested to see if it is an array.
373      * @returns <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a> True if an object is an array, otherwise false.
374      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
375      */
376     Object.isArray = function (someArray) {
377         var result = false;
378         if (Object.isDefined(someArray)) {
379             if (someArray.constructor.toString().indexOf("Array") > -1) {
380                 result = true;
381             }
382         }
383 
384         return result;
385     };
386 
387     /**
388      * <p>Static function that tells you whether an object is a date or not.</p>
389      * @static
390      * @param <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures">Object of some type</a> The object that will be tested to see if it is a date.
391      * @returns <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a> True if an object is an date, otherwise false.
392      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
393      */
394     Object.isDate = function (someDate) {
395         var result = false;
396         if (Object.isDefined(someDate)) {
397             if (typeof someDate === "object" && someDate instanceof Date) {
398                 result = true;
399             }
400         }
401 
402         return result;
403     };
404     /**
405      * <p>Static function that tells you whether an object is a string or not.</p>
406      * @static
407      * @param <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures">Object of some type</a> The object that will be tested to see if it is a string.
408      * @returns <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a> True if an object is an string, otherwise false.
409      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
410      */
411     Object.isString = function (someString) {
412         var result = false;
413         if (Object.isDefined(someString)) {
414             if (typeof someString === "string" || (typeof someString === "object" && someString instanceof String)) {
415                 result = true;
416             }
417         }
418 
419         return result;
420     };
421 
422     /**
423      * <p>Static function that tells you whether an object is numeric or not.</p>
424      * @static
425      * @param <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures">Object of some type</a> The object that will be tested to see if it is numeric.
426      * @returns <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a> True if an object is numeric, otherwise false.
427      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
428      */
429     Object.isNumeric = function (someNumber) {
430         var result = false;
431         if (Object.isDefined(someNumber)) {
432             if (typeof someNumber === "number" || (typeof someNumber === "object" && someNumber instanceof Number)) {
433                 result = true;
434             }
435         }
436 
437         return result;
438     };
439 
440     /**
441      * <p>Static function that tells you whether an object is a boolean or not.</p>
442      * @static
443      * @param <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures">Object of some type</a> The object that will be tested to see if it is a boolean.
444      * @returns <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a> True if an object is a boolean, otherwise false.
445      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
446      */
447     Object.isBoolean = function (someBoolean) {
448         var result = false;
449         if (Object.isDefined(someBoolean)) {
450             if (typeof someBoolean === "boolean" || (typeof someBoolean === "object" && someBoolean instanceof Boolean)) {
451                 result = true;
452             }
453         }
454 
455         return result;
456     };
457 
458     /**
459      * <p>Static function that tells you whether an object is defined or not.</p>
460      * @static
461      * @param <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures">Object of some type</a> The object that will be tested to see if it is defined.
462      * @returns <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</a> True if an object is defined, otherwise false.
463      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
464      */
465     Object.isDefined = function (target) {
466         var result = false;
467         if (target !== undefined && target !== null) {
468             result = true;
469         }
470         return result;
471     };
472     /* END Object Extensions *
473      ****************************************************************************************************/
474 
475     /****************************************************************************************************
476      * BEGIN String Extensions */
477     /**
478      * <p>Function that is used to trim the white spaces from the beginning and end of the string.</p>
479      * @function
480      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_string.asp">String</a> The value of the string after it has been trimmed.
481      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
482      */
483     String.prototype.trim = function () {
484         return this.replace(/^\s+|\s+$/g, '');
485     };
486 
487     /**
488      * <p>Function that is used to determine if a string includes a certain character or string.</p>
489      * @function
490      * @param <a href="http://www.w3schools.com/jsref/jsref_obj_string.asp">String</a> The string we are checking if is included.
491      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_boolean.asp">Boolean</a> True of the string is included, otherwise false.
492      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
493      */
494     if (!String.prototype.includes) {
495         String.prototype.includes = function () {
496             return String.prototype.indexOf.apply(this, arguments) !== -1;
497         };
498     }
499 
500     /**
501      * <p>Function that is used to format a sentence to camel case. (e.g. Hello world => helloWorld).</p>
502      * @function
503      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_string.asp">String</a> The value of the string after it has been formatted to camel case.
504      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
505      */
506     String.prototype.toCamelCase = function () {
507         return this.replace(/^([A-Z])|\s(\w)/g, function (match, p1, p2) {
508             if (p2) {
509                 return p2.toUpperCase();
510             }
511             return p1.toLowerCase();
512         });
513     };
514 
515     /**
516      * <p>Function that is used to turn a string that is in camel case format to a Normal sentence format. (e.g. helloWorld => Hello World)</p>
517      * @function
518      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_string.asp">String</a> The value of the string after it has been formatted to a normal sentence format.
519      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
520      */
521     String.prototype.toNormalCase = function () {
522         return this.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/([A-Z])([A-Z])/g, '$1 $2').replace(/^./, function (str) {return str.toUpperCase(); });
523     };
524 
525     /**
526      * <p>Convenience function that will format a string with dynamic variables.</p>
527      * @static
528      * @param {...string} string - first argument is the string to be formatted.  The remaining arguments are the format items (e.g. "{0}")
529      * @function
530      * @return <a href="http://www.w3schools.com/jsref/jsref_obj_string.asp">String</a> The value of the string after it has been formatted.
531      * @author <a href="mailto:pouncilt.developer@gmail.com">Tonté Pouncil</a>
532      */
533     String.format = function (someString) {
534         // The string containing the format items (e.g. "{0}")
535         // will and always has to be the first argument.
536         var theString = someString, i, regEx;
537 
538         // start with the second argument (i = 1)
539         for (i = 0; i < arguments.length; i = i + 1) {
540             // "gm" = RegEx options for Global search (more than one instance)
541             // and for Multiline search
542             regEx = new RegExp("\\{" + i + "\\}", "gm");
543             theString = theString.replace(regEx, arguments[i]);
544         }
545 
546         return theString;
547     };
548     /* END String Extensions *****************************************************************************************************/
549 
550 
551     BytePushers.namespace = function (ns_string) {
552         var parts = ns_string.split('.'), parent = BytePushers;
553         // strip redundant leading global
554         if (parts[0] === "BytePushers") {
555             parts = parts.slice(1);
556         }
557         parts.forEach(function (part, index) {
558             // create a property if it doesn't exist
559             if (parent[part] === undefined) {
560                 parent[part] = {};
561             }
562             parent = parent[part];
563         });
564         return parent;
565     };
566 
567     /**
568      * inherit() returns a newly created object that inherits properties from the prototype object p.
569      * It uses the ECMAScript 5 function Object.create() if it is defined, and otherwise falls.
570      *
571      * @param p
572      * @returns {*}
573      */
574     BytePushers.inherit = function (p) {
575         var t;
576         if (p === null) { // p must be non-null object
577             throw new TypeError();
578         }
579         if (Object.create) {            // if Object.create() is defined...
580             return Object.create(p);    //      then just use it.
581         }
582 
583         t = typeof p;               // Otherwise do some more type checking
584 
585         if (t !== "object" && t !== "function") {
586             throw new TypeError();
587         }
588 
589         function F() {// Define a dummy constructor function.
590             return;
591         }
592         F.prototype = p;                // Set its prototype property to p.
593         return new F();                 // Use f() to create an "heir" of p.
594     };
595 
596     /**
597      * defineClass() -- a utility function for defining JavaScript classes.
598      *
599      * This function expects a single object as its only argument.  It defines
600      * a new JavaScript class based on the data in that object and returns the
601      * constructor function of the new class.  This function handles the repetitive
602      * tasks of defining classes: setting up the prototype object for correct
603      * inheritance, copying methods from other types, and so on.
604      *
605      * The object passed as an argument should have some or all of the
606      * following properties:
607      *
608      *      name: the name of the class being defined.
609      *            If specified, this value will be stored in the classname
610      *            property of the prototype object.
611      *
612      *    extend: The constructor of the class to be extended.  If omitted,
613      *            the Object() constructor will be used.  This value will
614      *            be stored in the superclass property of the prototype object.
615      *
616      * construct: The constructor function for the class. If omitted, a new
617      *            empty function will be used.  This value becomes the return
618      *            value of the function, and is also stored in the constructor
619      *            property of the prototype object.
620      *
621      *   methods: An object that specifies the instance methods (and other shared
622      *            properties) for the class.  The properties of this object are
623      *            copied into the prototype object of the class.  If omitted,
624      *            an empty object is used instead.  Properties named
625      *            "classname", "superclass", and "constructor" are reserved
626      *            and should not be used in this object.
627      *
628      *   statics: An object that specifies the static methods (and other static
629      *            properties) for the class.  The properties of this object become
630      *            properties of the constructor function.  If omitted, an empty
631      *            object is used instead.
632      *
633      *   borrows: A constructor function or array of constructor functions.
634      *            The instance methods of each of the specified classes are copied
635      *            into the prototype object of this new class so that the
636      *            new class borrows the methods of each specified class.
637      *            Constructors are processed in the order they are specified,
638      *            so the methods of a class listed at the end of the array may
639      *            overwrite the methods of those specified earlier. Note that
640      *            borrowed methods are stored in the prototype object before
641      *            the properties of the methods object above.  Therefore,
642      *            methods specified in the methods object can overwrite borrowed
643      *            methods. If this property is not specified, no methods are
644      *            borrowed.
645      *
646      *  provides: A constructor function or array of constructor functions.
647      *            After the prototype object is fully initialized, this function
648      *            verifies that the prototype includes methods whose names and
649      *            number of arguments match the instance methods defined by each
650      *            of these classes.  No methods are copied; this is simply an
651      *            assertion that this class "provides" the functionality of the
652      *            specified classes.  If the assertion fails, this method will
653      *            throw an exception.  If no exception is thrown, any
654      *            instance of the new class can also be considered (using "duck
655      *            typing") to be an instance of these other types.  If this
656      *            property is not specified, no such verification is performed.
657      **/
658     BytePushers.defineClass = function (data) {
659         // Extract the fields we'll use from the argument object.
660         // Set up default values.
661         var classname = data.name,
662             Superclass = data.extend || Object,
663             constructor = data.construct || function () {return; },
664             methods = data.methods || {},
665             statics = data.statics || {},
666             borrows,
667             provides,
668             proto,
669             i1,
670             i2,
671             c1,
672             c2,
673             p1,
674             p2,
675             p3,
676             p4,
677             p5;
678 
679         // Borrows may be a single constructor or an array of them.
680         if (!data.borrows) {
681             borrows = [];
682         } else if (data.borrows instanceof Array) {
683             borrows = data.borrows;
684         } else {
685             borrows = [ data.borrows ];
686         }
687 
688         // Ditto for the provides property.
689         if (!data.provides) {
690             provides = [];
691         } else if (data.provides instanceof Array) {
692             provides = data.provides;
693         } else {
694             provides = [ data.provides ];
695         }
696 
697         // Create the object that will become the prototype for our class.
698         proto = new Superclass();
699 
700         // Delete any noninherited properties of this new prototype object.
701         for (p1 in proto) {
702             if (proto.hasOwnProperty(p1)) {
703                 delete proto[p1];
704             }
705         }
706 
707         // Borrow methods from "mixin" classes by copying to our prototype.
708         for (i1 = 0; i1 < borrows.length; i1 = i1 + 1) {
709             c1 = data.borrows[i1];
710             borrows[i1] = c1;
711             // Copy method properties from prototype of c to our prototype
712             for (p2 in c1.prototype) {
713                 if (typeof c1.prototype[p2] === "function") {
714                     proto[p2] = c1.prototype[p2];
715                 }
716             }
717         }
718 
719         // Copy instance methods to the prototype object
720         // This may overwrite methods of the mixin classes
721         for (p3 in methods) {
722             if (methods.hasOwnProperty(p3)) {
723                 proto[p3] = methods[p3];
724             }
725         }
726 
727         // Set up the reserved "constructor", "superclass", and "classname"
728         // properties of the prototype.
729         proto.constructor = constructor;
730         proto.Superclass = Superclass;
731         // classname is set only if a name was actually specified.
732         if (classname) {
733             proto.classname = classname;
734         }
735 
736         // Verify that our prototype provides all of the methods it is supposed to.
737         for (i2 = 0; i2 < provides.length; i2 = i2 + 1) {  // for each class
738             c2 = provides[i2];
739             for (p4 in c2.prototype) {   // for each property
740                 if (typeof c2.prototype[p4] === "function" && (p4 === "constructor" || p4 === "superclass")) { //methods only
741                     // Check that we have a method with the same name and that
742                     // it has the same number of declared arguments.  If so, move on
743                     if (proto.hasOwnProperty(p4) && typeof proto[p4] !== "function" && proto[p4].length !== c2.prototype[p4].length) {
744                         // Otherwise, throw an exception
745                         throw new Error("Class " + classname + " does not provide method " + c2.classname + "." + p4);
746                     }
747                 }
748             }
749         }
750 
751         // Associate the prototype object with the constructor function
752         constructor.prototype = proto;
753 
754         // Copy static properties to the constructor
755         for (p5 in statics) {
756             if (statics.hasOwnProperty(p5)) {
757                 constructor[p5] = statics[p5];
758             }
759         }
760 
761         // Finally, return the constructor function
762         return constructor;
763     };
764 
765     BytePushers.isArrayLike = function (x) {
766         if (x instanceof Array) { // Real arrays are array-like
767             return true;
768         }
769         if (!x.hasOwnProperty("length")) { // Arrays must have a length property
770             return false;
771         }
772         if (typeof x.length !== "number") { // Length must be a number
773             return false;
774         }
775         if (x.length < 0) { // and nonnegative
776             return false;
777         }
778         if (x.length > 0) {
779             // If the array is nonempty, it must at a minimum
780             // have a property defined whose name is the number length-1
781             if (!x.hasOwnProperty((x.length - 1))) {
782                 return false;
783             }
784         }
785         return true;
786     };
787 
788     // Return true if O has methods with the same name and arity as all
789     // methods in I.prototype. Otherwise, return false.  Throws an exception
790     // if I is a built-in type with nonenumerable methods.
791     BytePushers.provides = function (O, I) {
792         var proto = I.prototype,
793             p6;
794         // If O actually is an instance of I, it obviously looks like I
795         if (O instanceof I) {
796             return true;
797         }
798 
799         // If a constructor was passed instead of an object, use its prototype
800         if (typeof O === "function") {
801             O = O.prototype;
802         }
803 
804         // The methods of built-in types are not enumerable, and we return
805         // undefined.  Otherwise any object would appear to provide any of
806         // the built-in types.
807         if (I === Array || I === Boolean || I === Date || I === Error || I === Function || I === Number || I === RegExp || I === String) {
808             return undefined;
809         }
810 
811         for (p6 in proto) {  // Loop through all properties in I.prototype
812             // Ignore properties that are not functions
813             if (typeof proto[p6] === "function") {
814                 // If O does not have a property by the same name return false
815                 if (!(O.hasOwnProperty(p6))) {
816                     return false;
817                 }
818                 // If that property is not a function, return false
819                 if (typeof O[p6] !== "function") {
820                     return false;
821                 }
822                 // If the two functions are not declared with the same number
823                 // of arguments return false.
824                 if (O[p6].length !== proto[p6].length) {
825                     return false;
826                 }
827             }
828         }
829         // If all the methods check out, we can finally return true.
830         return true;
831     };
832 
833     // This function creates a new enumerated type. The argument object specifies // the names and values of each instance of the class. The return value
834     // is a constructor function that identifies the new class. Note, however
835     // that the constructor throws an exception: you can't use it to create new
836     // instances of the type. The returned constructor has properties that // map the name of a value to the value itself, and also a values array, // a foreach() iterator function
837     BytePushers.enumeration = function (namesToValues) {
838         // This is the dummy constructor function that will be the return value.
839         var name,
840             e,
841             i3,
842             enumeration = function () { throw "Can't Instantiate Enumerations"; },
843             proto;
844 
845         enumeration.prototype = { // Enumerated values inherit from this object.
846             constructor: enumeration, // Identify type
847             toString: function () { return this.name; }, // Return name
848             valueOf: function () { return this.value; }, // Return value
849             toJSON: function () { return this.name; } // For serialization
850         };
851         proto = enumeration;
852         enumeration.values = []; // An array of the enumerated value objects
853 
854         // Now create the instances of this new type.
855         for (name in namesToValues) {        // For each value
856             if (namesToValues.hasOwnProperty(name)) {
857                 e = BytePushers.inherit(proto);         // Create an object to represent it
858                 e.name = name;                  // Give it a name
859                 e.value = namesToValues[name];  // And a value
860                 enumeration[name] = e;          // Make it a property of constructor
861                 enumeration.values.push(e);     // And store in the values array
862             }
863         }
864 
865         // A class method for iterating the instances of the class
866         enumeration.foreach = function (f, c) {
867             for (i3 = 0; i3 < this.values.length; i3 = i3 + 1) {
868                 f.call(c, this.values[i3]);
869             }
870         };
871         // Return the constructor that identifies the new type
872         return enumeration;
873     };
874 }(window, document));