1 if (!Array.prototype.indexOf) {
  2   Array.prototype.indexOf = function(value, from) {
  3     var len = this.length >>> 0;
  4     from = Number(from) || 0;
  5     from = Math[from < 0 ? 'ceil' : 'floor'](from);
  6     if (from < 0) {
  7       from += len;
  8     }
  9     for (; from < len; from++) {
 10       if (from in this && this[from] === value) {
 11         return from;
 12       }
 13     }
 14     return -1;
 15   };
 16 }
 17 
 18 if (!Array.prototype.forEach) {
 19   Array.prototype.forEach = function(fn, context) {
 20     for (var i = 0, len = this.length >>> 0; i < len; i++) {
 21       if (i in this) {
 22         fn.call(context, this[i], i, this);
 23       }  
 24     }
 25   };
 26 }
 27 
 28 if (!Array.prototype.map) {
 29   Array.prototype.map = function(fn, context) {
 30     var result = [ ];
 31     for (var i = 0, len = this.length >>> 0; i < len; i++) {
 32       if (i in this) {
 33         result[i] = fn.call(context, this[i], i, this);
 34       }
 35     }
 36     return result;
 37   };
 38 }
 39 
 40 if (!Array.prototype.every) {
 41   Array.prototype.every = function(fn, context) {
 42     for (var i = 0, len = this.length >>> 0; i < len; i++) {
 43       if (i in this && !fn.call(context, this[i], i, this)) {
 44         return false;
 45       }
 46     }
 47     return true;
 48   };
 49 }
 50 
 51 if (!Array.prototype.some) {
 52   Array.prototype.some = function(fn, context) {
 53     for (var i = 0, len = this.length >>> 0; i < len; i++) {
 54       if (i in this && fn.call(context, this[i], i, this)) {
 55         return true;
 56       }
 57     }
 58     return false;
 59   };
 60 }
 61 
 62 if (!Array.prototype.filter) {
 63   Array.prototype.filter = function(fn, context) {
 64     var result = [ ], val;
 65     for (var i = 0, len = this.length >>> 0; i < len; i++) {
 66       if (i in this) {
 67         val = this[i]; // in case fn mutates this
 68         if (fn.call(context, val, i, this)) {
 69           result.push(val);
 70         }
 71       }
 72     }
 73     return result;
 74   };
 75 }
 76 
 77 if (!Array.prototype.reduce) {
 78   Array.prototype.reduce = function(fn /*, initial*/) {
 79     var len = this.length >>> 0,
 80         i = 0,
 81         rv;
 82         
 83     if (arguments.length > 1) {
 84       rv = arguments[1];
 85     }
 86     else {
 87       do {
 88         if (i in this) {
 89           rv = this[i++];
 90           break;
 91         }
 92         // if array contains no values, no initial value to return
 93         if (++i >= len) {
 94           throw new TypeError();
 95         }
 96       }
 97       while (true);
 98     }
 99     for (; i < len; i++) {
100       if (i in this) {
101         rv = fn.call(null, rv, this[i], i, this);
102       }
103     }
104     return rv;
105   };
106 }
107 
108 /**
109  * Invokes method on all items in a given array
110  * @method invoke
111  * @memberOf fabric.util.array
112  * @param {Array} array Array to iterate over
113  * @param {String} method Name of a method to invoke
114  */
115 function invoke(array, method) {
116   var args = slice.call(arguments, 2), result = [ ];
117   for (var i = 0, len = array.length; i < len; i++) {
118     result[i] = args.length ? array[i][method].apply(array[i], args) : array[i][method].call(array[i]);
119   }
120   return result;
121 }
122 
123 /**
124  * Finds maximum value in array (not necessarily "first" one)
125  * @method max
126  * @memberOf fabric.util.array
127  * @param {Array} array Array to iterate over
128  * @param {String} byProperty
129  */
130 function max(array, byProperty) {
131   var i = array.length - 1, 
132       result = byProperty ? array[i][byProperty] : array[i];
133   if (byProperty) {
134     while (i--) {
135       if (array[i][byProperty] >= result) {
136         result = array[i][byProperty];
137       }
138     }
139   }
140   else {
141     while (i--) {
142       if (array[i] >= result) {
143         result = array[i];
144       }
145     }
146   }
147   return result;
148 }
149 
150 /**
151  * Finds minimum value in array (not necessarily "first" one)
152  * @method min
153  * @memberOf fabric.util.array
154  * @param {Array} array Array to iterate over
155  * @param {String} byProperty
156  */
157 function min(array, byProperty) {
158   var i = array.length - 1, 
159       result = byProperty ? array[i][byProperty] : array[i];
160       
161   if (byProperty) {
162     while (i--) {
163       if (array[i][byProperty] < result) {
164         result = array[i][byProperty];
165       }
166     }
167   }
168   else {
169     while (i--) {
170       if (array[i] < result) {
171         result = array[i];
172       }
173     }
174   }
175   return result;
176 }
177 
178 /** @namespace */
179 fabric.util.array = {
180   invoke: invoke,
181   min: min,
182   max: max
183 };