1(function() {
2
3  if ( !document.addEventListener && !document.removeEventListener && !document.dispatchEvent ) {
4    var events = {};
5
6    var addEventListener = function( eventName, callBack ) {
7
8      eventName = ( eventName === "DOMContentLoaded" ) ? "readystatechange" : eventName;
9
10      if ( Event[ eventName.toUpperCase() ] || eventName === "readystatechange" ) {
11        document.attachEvent( "on" + eventName, callBack );
12        return;
13      }
14
15      if ( !events[ eventName ] ) {
16        events[ eventName ] = {
17          events: [],
18          queue: [],
19          active: false
20        };
21      }
22
23      if ( events[ eventName ].active ) {
24        events[ eventName ].queue.push( callBack );
25      } else {
26        events[ eventName ].events.push( callBack );
27      }
28    };
29
30    var removeEventListener = function( eventName, callBack ) {
31
32      eventName = ( eventName === "DOMContentLoaded" ) ? "readystatechange" : eventName;
33
34      var i = 0,
35          listeners = events[ eventName ];
36
37      if ( Event[ eventName.toUpperCase() ] || eventName === "readystatechange" ) {
38        document.detachEvent( "on" + eventName, callBack );
39        return;
40      }
41
42      if ( !listeners ) {
43        return;
44      }
45
46      for ( i = listeners.events.length - 1; i >= 0; i-- ) {
47        if ( callBack === listeners.events[ i ] ) {
48          delete listeners.events[ i ];
49        }
50      }
51
52      for ( i = listeners.queue.length - 1; i >= 0; i-- ) {
53        if ( callBack === listeners.queue[ i ] ) {
54          delete listeners.queue[ i ];
55        }
56      }
57    };
58
59    var dispatchEvent = function( eventObject ) {
60      var evt,
61          self = this,
62          eventInterface,
63          listeners,
64          eventName = eventObject.type,
65          queuedListener;
66
67      // A string was passed, create event object
68      if ( !eventName ) {
69
70        eventName = eventObject;
71        eventInterface  = Popcorn.events.getInterface( eventName );
72
73        if ( eventInterface ) {
74
75          evt = document.createEvent( eventInterface );
76          evt.initCustomEvent( eventName, true, true, window, 1 );
77        }
78      }
79
80      listeners = events[ eventName ];
81
82      if ( listeners ) {
83        listeners.active = true;
84
85        for ( var i = 0; i < listeners.events.length; i++ ) {
86          if ( listeners.events[ i ] ) {
87            listeners.events[ i ].call( self, evt, self );
88          }
89        }
90
91        if ( listeners.queue.length ) {
92          while ( listeners.queue.length ) {
93            queuedListener = listeners.queue.shift();
94
95            if ( queuedListener ) {
96              listeners.events.push( queuedListener );
97            }
98          }
99        }
100
101        listeners.active = false;
102
103        listeners.events.forEach(function( listener ) {
104          if ( !listener ) {
105            listeners.events.splice( listeners.events.indexOf( listener ), 1 );
106          }
107        });
108
109        listeners.queue.forEach(function( listener ) {
110          if ( !listener ) {
111            listeners.queue.splice( listeners.queue.indexOf( listener ), 1 );
112          }
113        });
114      }
115    };
116
117    document.addEventListener = addEventListener;
118    document.removeEventListener = removeEventListener;
119    document.dispatchEvent = dispatchEvent;
120
121  }
122
123  if ( !Event.prototype.preventDefault ) {
124    Event.prototype.preventDefault = function() {
125      this.returnValue = false;
126    };
127  }
128  if ( !Event.prototype.stopPropagation ) {
129    Event.prototype.stopPropagation = function() {
130      this.cancelBubble = true;
131    };
132  }
133
134  window.addEventListener = window.addEventListener || function( event, callBack ) {
135
136    event = "on" + event;
137
138    window.attachEvent( event, callBack );
139  };
140
141  window.removeEventListener = window.removeEventListener || function( event, callBack ) {
142
143    event = "on" + event;
144
145    window.detachEvent( event, callBack );
146  };
147
148  HTMLScriptElement.prototype.addEventListener = HTMLScriptElement.prototype.addEventListener || function( event, callBack ) {
149
150    event = ( event === "load" ) ? "onreadystatechange" : "on" + event;
151
152    if( event === "onreadystatechange" ){
153      callBack.readyStateCheck = callBack.readyStateCheck || function( e ){
154
155        if( self.readyState === "loaded" ){
156          callBack( e );
157        }
158      };
159    }
160
161    this.attachEvent( event, ( callBack.readyStateCheck || callBack ) );
162  };
163
164  HTMLScriptElement.prototype.removeEventListener = HTMLScriptElement.prototype.removeEventListener || function( event, callBack ) {
165
166    event = ( event === "load" ) ? "onreadystatechange" : "on" + event;
167
168    this.detachEvent( event, ( callBack.readyStateCheck || callBack ) );
169  };
170
171  document.createEvent = document.createEvent || function ( type ) {
172
173    return {
174      type : null,
175      target : null,
176      currentTarget : null,
177      cancelable : false,
178      detail: false,
179      bubbles : false,
180      initEvent : function (type, bubbles, cancelable)  {
181        this.type = type;
182      },
183      initCustomEvent: function(type, bubbles, cancelable, detail) {
184        this.type = type;
185        this.detail = detail;
186      },
187      stopPropagation : function () {},
188      stopImmediatePropagation : function () {}
189    }
190  };
191
192  Array.prototype.forEach = Array.prototype.forEach || function( fn, context ) {
193
194    var obj = this,
195        hasOwn = Object.prototype.hasOwnProperty;
196
197    if ( !obj || !fn ) {
198      return {};
199    }
200
201    context = context || this;
202
203    var key, len;
204
205    for ( key in obj ) {
206      if ( hasOwn.call( obj, key ) ) {
207        fn.call( context, obj[ key ], key, obj );
208      }
209    }
210    return obj;
211  };
212
213  // Production steps of ECMA-262, Edition 5, 15.4.4.19
214  // Reference: http://es5.github.com/#x15.4.4.19
215  if ( !Array.prototype.map ) {
216
217    Array.prototype.map = function( callback, thisArg ) {
218
219      var T, A, k;
220
221      if ( this == null ) {
222        throw new TypeError( "this is null or not defined" );
223      }
224
225      // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
226      var O = Object( this );
227
228      // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
229      // 3. Let len be ToUint32(lenValue).
230      var len = O.length >>> 0;
231
232      // 4. If IsCallable(callback) is false, throw a TypeError exception.
233      // See: http://es5.github.com/#x9.11
234      if ( {}.toString.call( callback ) != "[object Function]" ) {
235        throw new TypeError( callback + " is not a function" );
236      }
237
238      // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
239      if ( thisArg ) {
240        T = thisArg;
241      }
242
243      // 6. Let A be a new array created as if by the expression new Array(len) where Array is
244      // the standard built-in constructor with that name and len is the value of len.
245      A = new Array( len );
246
247      // 7. Let k be 0
248      k = 0;
249
250      // 8. Repeat, while k < len
251      while( k < len ) {
252
253        var kValue, mappedValue;
254
255        // a. Let Pk be ToString(k).
256        //   This is implicit for LHS operands of the in operator
257        // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
258        //   This step can be combined with c
259        // c. If kPresent is true, then
260        if ( k in O ) {
261
262          // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
263          kValue = O[ k ];
264
265          // ii. Let mappedValue be the result of calling the Call internal method of callback
266          // with T as the this value and argument list containing kValue, k, and O.
267          mappedValue = callback.call( T, kValue, k, O );
268
269          // iii. Call the DefineOwnProperty internal method of A with arguments
270          // Pk, Property Descriptor {Value: mappedValue, Writable: true, Enumerable: true, Configurable: true},
271          // and false.
272
273          // In browsers that support Object.defineProperty, use the following:
274          // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
275
276          // For best browser support, use the following:
277          A[ k ] = mappedValue;
278        }
279        // d. Increase k by 1.
280        k++;
281      }
282
283      // 9. return A
284      return A;
285    };
286  }
287
288  if ( !Array.prototype.indexOf ) {
289
290    Array.prototype.indexOf = function ( searchElement /*, fromIndex */ ) {
291
292      if ( this == null) {
293
294        throw new TypeError();
295      }
296
297      var t = Object( this ),
298          len = t.length >>> 0;
299
300      if ( len === 0 ) {
301
302        return -1;
303      }
304
305      var n = 0;
306
307      if ( arguments.length > 0 ) {
308
309        n = Number( arguments[ 1 ] );
310
311        if ( n != n ) { // shortcut for verifying if it's NaN
312
313          n = 0;
314        } else if ( n != 0 && n != Infinity && n != -Infinity ) {
315
316          n = ( n > 0 || -1 ) * Math.floor( Math.abs( n ) );
317        }
318      }
319
320      if ( n >= len ) {
321        return -1;
322      }
323
324      var k = n >= 0 ? n : Math.max( len - Math.abs( n ), 0 );
325
326      for (; k < len; k++ ) {
327
328        if ( k in t && t[ k ] === searchElement ) {
329
330          return k;
331        }
332      }
333
334      return -1;
335    }
336  }
337
338  if ( typeof String.prototype.trim !== "function" ) {
339
340    String.prototype.trim = function() {
341      return this.replace(/^\s+|\s+$/g, "");
342    };
343  }
344
345  // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
346  if (!Object.keys) {
347    Object.keys = (function () {
348      'use strict';
349      var hasOwnProperty = Object.prototype.hasOwnProperty,
350          hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
351          dontEnums = [
352            'toString',
353            'toLocaleString',
354            'valueOf',
355            'hasOwnProperty',
356            'isPrototypeOf',
357            'propertyIsEnumerable',
358            'constructor'
359          ],
360          dontEnumsLength = dontEnums.length;
361
362      return function (obj) {
363        if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
364          throw new TypeError('Object.keys called on non-object');
365        }
366
367        var result = [], prop, i;
368
369        for (prop in obj) {
370          if (hasOwnProperty.call(obj, prop)) {
371            result.push(prop);
372          }
373        }
374
375        if (hasDontEnumBug) {
376          for (i = 0; i < dontEnumsLength; i++) {
377            if (hasOwnProperty.call(obj, dontEnums[i])) {
378              result.push(dontEnums[i]);
379            }
380          }
381        }
382        return result;
383      };
384    }());
385  }
386
387  if ( !Object.defineProperties ) {
388    Object.defineProperties = function(obj, properties) {
389      function convertToDescriptor(desc) {
390        function hasProperty(obj, prop) {
391          return Object.prototype.hasOwnProperty.call(obj, prop);
392        }
393
394        function isCallable(v) {
395          // NB: modify as necessary if other values than functions are callable.
396          return typeof v === "function";
397        }
398
399        if (typeof desc !== "object" || desc === null)
400          throw new TypeError("bad desc");
401
402        var d = {};
403
404        if (hasProperty(desc, "enumerable"))
405          d.enumerable = !!obj.enumerable;
406        if (hasProperty(desc, "configurable"))
407          d.configurable = !!desc.configurable;
408        if (hasProperty(desc, "value"))
409          d.value = obj.value;
410        if (hasProperty(desc, "writable"))
411          d.writable = !!desc.writable;
412        if ( hasProperty(desc, "get") ) {
413          var g = desc.get;
414
415          if (!isCallable(g) && g !== "undefined")
416            throw new TypeError("bad get");
417          d.get = g;
418        }
419        if ( hasProperty(desc, "set") ) {
420          var s = desc.set;
421          if (!isCallable(s) && s !== "undefined")
422            throw new TypeError("bad set");
423          d.set = s;
424        }
425
426        if (("get" in d || "set" in d) && ("value" in d || "writable" in d))
427          throw new TypeError("identity-confused descriptor");
428
429        return d;
430      }
431
432      if (typeof obj !== "object" || obj === null)
433        throw new TypeError("bad obj");
434
435      properties = Object(properties);
436
437      var keys = Object.keys(properties);
438      var descs = [];
439
440      for (var i = 0; i < keys.length; i++)
441        descs.push([keys[i], convertToDescriptor(properties[keys[i]])]);
442
443      for (var i = 0; i < descs.length; i++)
444        Object.defineProperty(obj, descs[i][0], descs[i][1]);
445
446      return obj;
447    };
448  }
449
450})();
451