1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * The main namespace of Cocos2d-JS, all engine core classes, functions, properties and constants are defined in this namespace
 28  * @namespace
 29  * @name cc
 30  */
 31 var cc = cc || {};
 32 cc._tmp = cc._tmp || {};
 33 cc._LogInfos = {};
 34 
 35 /** @expose */
 36 window._p;
 37 _p = window;
 38 /** @expose */
 39 _p.gl;
 40 /** @expose */
 41 _p.WebGLRenderingContext;
 42 /** @expose */
 43 _p.DeviceOrientationEvent;
 44 /** @expose */
 45 _p.DeviceMotionEvent;
 46 /** @expose */
 47 _p.AudioContext;
 48 /** @expose */
 49 _p.webkitAudioContext;
 50 /** @expose */
 51 _p.mozAudioContext;
 52 _p = Object.prototype;
 53 /** @expose */
 54 _p._super;
 55 /** @expose */
 56 _p.ctor;
 57 delete window._p;
 58 
 59 cc.newElement = function (x) {
 60     return document.createElement(x);
 61 };
 62 
 63 cc._addEventListener = function (element, type, listener, useCapture) {
 64     element.addEventListener(type, listener, useCapture);
 65 };
 66 
 67 //is nodejs ? Used to support node-webkit.
 68 cc._isNodeJs = typeof require !== 'undefined' && require("fs");
 69 
 70 /**
 71  * Iterate over an object or an array, executing a function for each matched element.
 72  * @param {object|array} obj
 73  * @param {function} iterator
 74  * @param {object} [context]
 75  */
 76 cc.each = function (obj, iterator, context) {
 77     if (!obj)
 78         return;
 79     if (obj instanceof Array) {
 80         for (var i = 0, li = obj.length; i < li; i++) {
 81             if (iterator.call(context, obj[i], i) === false)
 82                 return;
 83         }
 84     } else {
 85         for (var key in obj) {
 86             if (iterator.call(context, obj[key], key) === false)
 87                 return;
 88         }
 89     }
 90 };
 91 
 92 /**
 93  * Copy all of the properties in source objects to target object and return the target object.
 94  * @param {object} target
 95  * @param {object} *sources
 96  * @returns {object}
 97  */
 98 cc.extend = function(target) {
 99     var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : [];
100 
101     cc.each(sources, function(src) {
102         for(var key in src) {
103             if (src.hasOwnProperty(key)) {
104                 target[key] = src[key];
105             }
106         }
107     });
108     return target;
109 };
110 
111 /**
112  * Check the obj whether is function or not
113  * @param {*} obj
114  * @returns {boolean}
115  */
116 cc.isFunction = function(obj) {
117     return typeof obj === 'function';
118 };
119 
120 /**
121  * Check the obj whether is number or not
122  * @param {*} obj
123  * @returns {boolean}
124  */
125 cc.isNumber = function(obj) {
126     return typeof obj === 'number' || Object.prototype.toString.call(obj) === '[object Number]';
127 };
128 
129 /**
130  * Check the obj whether is string or not
131  * @param {*} obj
132  * @returns {boolean}
133  */
134 cc.isString = function(obj) {
135     return typeof obj === 'string' || Object.prototype.toString.call(obj) === '[object String]';
136 };
137 
138 /**
139  * Check the obj whether is array or not
140  * @param {*} obj
141  * @returns {boolean}
142  */
143 cc.isArray = function(obj) {
144     return Array.isArray(obj) ||
145         (typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Array]');
146 };
147 
148 /**
149  * Check the obj whether is undefined or not
150  * @param {*} obj
151  * @returns {boolean}
152  */
153 cc.isUndefined = function(obj) {
154     return typeof obj === 'undefined';
155 };
156 
157 /**
158  * Check the obj whether is object or not
159  * @param {*} obj
160  * @returns {boolean}
161  */
162 cc.isObject = function(obj) {
163     return typeof obj === "object" && Object.prototype.toString.call(obj) === '[object Object]';
164 };
165 
166 /**
167  * Check the url whether cross origin
168  * @param {String} url
169  * @returns {boolean}
170  */
171 cc.isCrossOrigin = function (url) {
172     if (!url) {
173         cc.log("invalid URL");
174         return false;
175     }
176     var startIndex = url.indexOf("://");
177     if (startIndex === -1)
178         return false;
179 
180     var endIndex = url.indexOf("/", startIndex + 3);
181     var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex);
182     return urlOrigin !== location.origin;
183 };
184 
185 //+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++
186 /**
187  * Async Pool class, a helper of cc.async
188  * @param {Object|Array} srcObj
189  * @param {Number} limit the limit of parallel number
190  * @param {function} iterator
191  * @param {function} onEnd
192  * @param {object} target
193  * @constructor
194  */
195 cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){
196     var self = this;
197     self._srcObj = srcObj;
198     self._limit = limit;
199     self._pool = [];
200     self._iterator = iterator;
201     self._iteratorTarget = target;
202     self._onEnd = onEnd;
203     self._onEndTarget = target;
204     self._results = srcObj instanceof Array ? [] : {};
205     self._isErr = false;
206 
207     cc.each(srcObj, function(value, index){
208         self._pool.push({index : index, value : value});
209     });
210 
211     self.size = self._pool.length;
212     self.finishedSize = 0;
213     self._workingSize = 0;
214 
215     self._limit = self._limit || self.size;
216 
217     self.onIterator = function(iterator, target){
218         self._iterator = iterator;
219         self._iteratorTarget = target;
220     };
221 
222     self.onEnd = function(endCb, endCbTarget){
223         self._onEnd = endCb;
224         self._onEndTarget = endCbTarget;
225     };
226 
227     self._handleItem = function(){
228         var self = this;
229         if(self._pool.length === 0 || self._workingSize >= self._limit)
230             return;                                                         //return directly if the array's length = 0 or the working size great equal limit number
231 
232         var item = self._pool.shift();
233         var value = item.value, index = item.index;
234         self._workingSize++;
235         self._iterator.call(self._iteratorTarget, value, index,
236             function(err) {
237                 if (self._isErr)
238                     return;
239 
240                 self.finishedSize++;
241                 self._workingSize--;
242                 if (err) {
243                     self._isErr = true;
244                     if (self._onEnd)
245                         self._onEnd.call(self._onEndTarget, err);
246                     return;
247                 }
248 
249                 var arr = Array.prototype.slice.call(arguments, 1);
250                 self._results[this.index] = arr[0];
251                 if (self.finishedSize === self.size) {
252                     if (self._onEnd)
253                         self._onEnd.call(self._onEndTarget, null, self._results);
254                     return;
255                 }
256                 self._handleItem();
257             }.bind(item),
258             self);
259     };
260 
261     self.flow = function(){
262         var self = this;
263         if(self._pool.length === 0) {
264             if(self._onEnd)
265                 self._onEnd.call(self._onEndTarget, null, []);
266                 return;
267         }
268         for(var i = 0; i < self._limit; i++)
269             self._handleItem();
270     }
271 };
272 
273 /**
274  * @class
275  */
276 cc.async = /** @lends cc.async# */{
277     /**
278      * Do tasks series.
279      * @param {Array|Object} tasks
280      * @param {function} [cb] callback
281      * @param {Object} [target]
282      * @return {cc.AsyncPool}
283      */
284     series : function(tasks, cb, target){
285         var asyncPool = new cc.AsyncPool(tasks, 1, function(func, index, cb1){
286             func.call(target, cb1);
287         }, cb, target);
288         asyncPool.flow();
289         return asyncPool;
290     },
291 
292     /**
293      * Do tasks parallel.
294      * @param {Array|Object} tasks
295      * @param {function} cb callback
296      * @param {Object} [target]
297      * @return {cc.AsyncPool}
298      */
299     parallel : function(tasks, cb, target){
300         var asyncPool = new cc.AsyncPool(tasks, 0, function(func, index, cb1){
301             func.call(target, cb1);
302         }, cb, target);
303         asyncPool.flow();
304         return asyncPool;
305     },
306 
307     /**
308      * Do tasks waterfall.
309      * @param {Array|Object} tasks
310      * @param {function} cb callback
311      * @param {Object} [target]
312      * @return {cc.AsyncPool}
313      */
314     waterfall : function(tasks, cb, target){
315         var args = [];
316         var lastResults = [null];//the array to store the last results
317         var asyncPool = new cc.AsyncPool(tasks, 1,
318             function (func, index, cb1) {
319                 args.push(function (err) {
320                     args = Array.prototype.slice.call(arguments, 1);
321                     if(tasks.length - 1 === index) lastResults = lastResults.concat(args);//while the last task
322                     cb1.apply(null, arguments);
323                 });
324                 func.apply(target, args);
325             }, function (err) {
326                 if (!cb)
327                     return;
328                 if (err)
329                     return cb.call(target, err);
330                 cb.apply(target, lastResults);
331             });
332         asyncPool.flow();
333         return asyncPool;
334     },
335 
336     /**
337      * Do tasks by iterator.
338      * @param {Array|Object} tasks
339      * @param {function|Object} iterator
340      * @param {function} [callback]
341      * @param {Object} [target]
342      * @return {cc.AsyncPool}
343      */
344     map : function(tasks, iterator, callback, target){
345         var locIterator = iterator;
346         if(typeof(iterator) === "object"){
347             callback = iterator.cb;
348             target = iterator.iteratorTarget;
349             locIterator = iterator.iterator;
350         }
351         var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, callback, target);
352         asyncPool.flow();
353         return asyncPool;
354     },
355 
356     /**
357      * Do tasks by iterator limit.
358      * @param {Array|Object} tasks
359      * @param {Number} limit
360      * @param {function} iterator
361      * @param {function} cb callback
362      * @param {Object} [target]
363      */
364     mapLimit : function(tasks, limit, iterator, cb, target){
365         var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target);
366         asyncPool.flow();
367         return asyncPool;
368     }
369 };
370 //+++++++++++++++++++++++++something about async end+++++++++++++++++++++++++++++++++
371 
372 //+++++++++++++++++++++++++something about path begin++++++++++++++++++++++++++++++++
373 /**
374  * @class
375  */
376 cc.path = /** @lends cc.path# */{
377     /**
378      * Join strings to be a path.
379      * @example
380      cc.path.join("a", "b.png");//-->"a/b.png"
381      cc.path.join("a", "b", "c.png");//-->"a/b/c.png"
382      cc.path.join("a", "b");//-->"a/b"
383      cc.path.join("a", "b", "/");//-->"a/b/"
384      cc.path.join("a", "b/", "/");//-->"a/b/"
385      * @returns {string}
386      */
387     join: function () {
388         var l = arguments.length;
389         var result = "";
390         for (var i = 0; i < l; i++) {
391             result = (result + (result === "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, "");
392         }
393         return result;
394     },
395 
396     /**
397      * Get the ext name of a path.
398      * @example
399      cc.path.extname("a/b.png");//-->".png"
400      cc.path.extname("a/b.png?a=1&b=2");//-->".png"
401      cc.path.extname("a/b");//-->null
402      cc.path.extname("a/b?a=1&b=2");//-->null
403      * @param {string} pathStr
404      * @returns {*}
405      */
406     extname: function (pathStr) {
407         var temp = /(\.[^\.\/\?\\]*)(\?.*)?$/.exec(pathStr);
408         return temp ? temp[1] : null;
409     },
410 
411     /**
412      * Get the main name of a file name
413      * @param {string} fileName
414      * @returns {string}
415      */
416     mainFileName: function(fileName){
417         if(fileName){
418            var idx = fileName.lastIndexOf(".");
419             if(idx !== -1)
420                return fileName.substring(0,idx);
421         }
422         return fileName;
423     },
424 
425     /**
426      * Get the file name of a file path.
427      * @example
428      cc.path.basename("a/b.png");//-->"b.png"
429      cc.path.basename("a/b.png?a=1&b=2");//-->"b.png"
430      cc.path.basename("a/b.png", ".png");//-->"b"
431      cc.path.basename("a/b.png?a=1&b=2", ".png");//-->"b"
432      cc.path.basename("a/b.png", ".txt");//-->"b.png"
433      * @param {string} pathStr
434      * @param {string} [extname]
435      * @returns {*}
436      */
437     basename: function (pathStr, extname) {
438         var index = pathStr.indexOf("?");
439         if (index > 0) pathStr = pathStr.substring(0, index);
440         var reg = /(\/|\\\\)([^(\/|\\\\)]+)$/g;
441         var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, ""));
442         if (!result) return null;
443         var baseName = result[2];
444         if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase())
445             return baseName.substring(0, baseName.length - extname.length);
446         return baseName;
447     },
448 
449     /**
450      * Get dirname of a file path.
451      * @example
452      * unix
453      cc.path.driname("a/b/c.png");//-->"a/b"
454      cc.path.driname("a/b/c.png?a=1&b=2");//-->"a/b"
455      cc.path.dirname("a/b/");//-->"a/b"
456      cc.path.dirname("c.png");//-->""
457      * windows
458      cc.path.driname("a\\b\\c.png");//-->"a\b"
459      cc.path.driname("a\\b\\c.png?a=1&b=2");//-->"a\b"
460      * @param {string} pathStr
461      * @returns {*}
462      */
463     dirname: function (pathStr) {
464         return pathStr.replace(/((.*)(\/|\\|\\\\))?(.*?\..*$)?/, '$2');
465     },
466 
467     /**
468      * Change extname of a file path.
469      * @example
470      cc.path.changeExtname("a/b.png", ".plist");//-->"a/b.plist"
471      cc.path.changeExtname("a/b.png?a=1&b=2", ".plist");//-->"a/b.plist?a=1&b=2"
472      * @param {string} pathStr
473      * @param {string} [extname]
474      * @returns {string}
475      */
476     changeExtname: function (pathStr, extname) {
477         extname = extname || "";
478         var index = pathStr.indexOf("?");
479         var tempStr = "";
480         if (index > 0) {
481             tempStr = pathStr.substring(index);
482             pathStr = pathStr.substring(0, index);
483         }
484         index = pathStr.lastIndexOf(".");
485         if (index < 0) return pathStr + extname + tempStr;
486         return pathStr.substring(0, index) + extname + tempStr;
487     },
488     /**
489      * Change file name of a file path.
490      * @example
491      cc.path.changeBasename("a/b/c.plist", "b.plist");//-->"a/b/b.plist"
492      cc.path.changeBasename("a/b/c.plist?a=1&b=2", "b.plist");//-->"a/b/b.plist?a=1&b=2"
493      cc.path.changeBasename("a/b/c.plist", ".png");//-->"a/b/c.png"
494      cc.path.changeBasename("a/b/c.plist", "b");//-->"a/b/b"
495      cc.path.changeBasename("a/b/c.plist", "b", true);//-->"a/b/b.plist"
496      * @param {String} pathStr
497      * @param {String} basename
498      * @param {Boolean} [isSameExt]
499      * @returns {string}
500      */
501     changeBasename: function (pathStr, basename, isSameExt) {
502         if (basename.indexOf(".") === 0) return this.changeExtname(pathStr, basename);
503         var index = pathStr.indexOf("?");
504         var tempStr = "";
505         var ext = isSameExt ? this.extname(pathStr) : "";
506         if (index > 0) {
507             tempStr = pathStr.substring(index);
508             pathStr = pathStr.substring(0, index);
509         }
510         index = pathStr.lastIndexOf("/");
511         index = index <= 0 ? 0 : index + 1;
512         return pathStr.substring(0, index) + basename + ext + tempStr;
513     }
514 };
515 //+++++++++++++++++++++++++something about path end++++++++++++++++++++++++++++++++
516 
517 //+++++++++++++++++++++++++something about loader start+++++++++++++++++++++++++++
518 /**
519  * Loader for resource loading process. It's a singleton object.
520  * @class
521  */
522 cc.loader = /** @lends cc.loader# */{
523     _jsCache: {},//cache for js
524     _register: {},//register of loaders
525     _langPathCache: {},//cache for lang path
526     _aliases: {},//aliases for res url
527 
528     resPath: "",//root path of resource
529     audioPath: "",//root path of audio
530     cache: {},//cache for data loaded
531 
532     /**
533      * Get XMLHttpRequest.
534      * @returns {XMLHttpRequest}
535      */
536     getXMLHttpRequest: function () {
537         return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP");
538     },
539 
540     //@MODE_BEGIN DEV
541 
542     _getArgs4Js: function (args) {
543         var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null];
544 
545         if (args.length === 1) {
546             results[1] = a0 instanceof Array ? a0 : [a0];
547         } else if (args.length === 2) {
548             if (typeof a1 === "function") {
549                 results[1] = a0 instanceof Array ? a0 : [a0];
550                 results[2] = a1;
551             } else {
552                 results[0] = a0 || "";
553                 results[1] = a1 instanceof Array ? a1 : [a1];
554             }
555         } else if (args.length === 3) {
556             results[0] = a0 || "";
557             results[1] = a1 instanceof Array ? a1 : [a1];
558             results[2] = a2;
559         } else throw "arguments error to load js!";
560         return results;
561     },
562 
563     /**
564      * Load js files.
565      * If the third parameter doesn't exist, then the baseDir turns to be "".
566      *
567      * @param {string} [baseDir]   The pre path for jsList or the list of js path.
568      * @param {array} jsList    List of js path.
569      * @param {function} [cb]  Callback function
570      * @returns {*}
571      */
572     loadJs: function (baseDir, jsList, cb) {
573         var self = this, localJsCache = self._jsCache,
574             args = self._getArgs4Js(arguments);
575 
576         var preDir = args[0], list = args[1], callback = args[2];
577         if (navigator.userAgent.indexOf("Trident/5") > -1) {
578             self._loadJs4Dependency(preDir, list, 0, callback);
579         } else {
580             cc.async.map(list, function (item, index, cb1) {
581                 var jsPath = cc.path.join(preDir, item);
582                 if (localJsCache[jsPath]) return cb1(null);
583                 self._createScript(jsPath, false, cb1);
584             }, callback);
585         }
586     },
587     /**
588      * Load js width loading image.
589      *
590      * @param {string} [baseDir]
591      * @param {array} jsList
592      * @param {function} [cb]
593      */
594     loadJsWithImg: function (baseDir, jsList, cb) {
595         var self = this, jsLoadingImg = self._loadJsImg(),
596             args = self._getArgs4Js(arguments);
597         this.loadJs(args[0], args[1], function (err) {
598             if (err) throw err;
599             jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif
600             if (args[2]) args[2]();
601         });
602     },
603     _createScript: function (jsPath, isAsync, cb) {
604         var d = document, self = this, s = cc.newElement('script');
605         s.async = isAsync;
606         self._jsCache[jsPath] = true;
607         if(cc.game.config["noCache"] && typeof jsPath === "string"){
608             if(self._noCacheRex.test(jsPath))
609                 s.src = jsPath + "&_t=" + (new Date() - 0);
610             else
611                 s.src = jsPath + "?_t=" + (new Date() - 0);
612         }else{
613             s.src = jsPath;
614         }
615         cc._addEventListener(s, 'load', function () {
616             s.parentNode.removeChild(s);
617             this.removeEventListener('load', arguments.callee, false);
618             cb();
619         }, false);
620         cc._addEventListener(s, 'error', function () {
621             s.parentNode.removeChild(s);
622             cb("Load " + jsPath + " failed!");
623         }, false);
624         d.body.appendChild(s);
625     },
626     _loadJs4Dependency: function (baseDir, jsList, index, cb) {
627         if (index >= jsList.length) {
628             if (cb) cb();
629             return;
630         }
631         var self = this;
632         self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) {
633             if (err) return cb(err);
634             self._loadJs4Dependency(baseDir, jsList, index + 1, cb);
635         });
636     },
637     _loadJsImg: function () {
638         var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg");
639         if (!jsLoadingImg) {
640             jsLoadingImg = cc.newElement('img');
641 
642             if (cc._loadingImage)
643                 jsLoadingImg.src = cc._loadingImage;
644 
645             var canvasNode = d.getElementById(cc.game.config["id"]);
646             canvasNode.style.backgroundColor = "black";
647             canvasNode.parentNode.appendChild(jsLoadingImg);
648 
649             var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle;
650             if (!canvasStyle)
651                 canvasStyle = {width: canvasNode.width, height: canvasNode.height};
652             jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px";
653             jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px";
654             jsLoadingImg.style.position = "absolute";
655         }
656         return jsLoadingImg;
657     },
658     //@MODE_END DEV
659 
660     /**
661      * Load a single resource as txt.
662      * @param {string} url
663      * @param {function} [cb] arguments are : err, txt
664      */
665     loadTxt: function (url, cb) {
666         if (!cc._isNodeJs) {
667             var xhr = this.getXMLHttpRequest(),
668                 errInfo = "load " + url + " failed!";
669             xhr.open("GET", url, true);
670             if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
671                 // IE-specific logic here
672                 xhr.setRequestHeader("Accept-Charset", "utf-8");
673                 xhr.onreadystatechange = function () {
674                     if(xhr.readyState === 4)
675                         xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo);
676                 };
677             } else {
678                 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
679                 xhr.onload = function () {
680                     if(xhr.readyState === 4)
681                         xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo);
682                 };
683             }
684             xhr.send(null);
685         } else {
686             var fs = require("fs");
687             fs.readFile(url, function (err, data) {
688                 err ? cb(err) : cb(null, data.toString());
689             });
690         }
691     },
692     _loadTxtSync: function (url) {
693         if (!cc._isNodeJs) {
694             var xhr = this.getXMLHttpRequest();
695             xhr.open("GET", url, false);
696             if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
697                 // IE-specific logic here
698                 xhr.setRequestHeader("Accept-Charset", "utf-8");
699             } else {
700                 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
701             }
702             xhr.send(null);
703             if (!xhr.readyState === 4 || xhr.status !== 200) {
704                 return null;
705             }
706             return xhr.responseText;
707         } else {
708             var fs = require("fs");
709             return fs.readFileSync(url).toString();
710         }
711     },
712 
713     loadCsb: function(url, cb){
714         var xhr = new XMLHttpRequest();
715         xhr.open("GET", url, true);
716         xhr.responseType = "arraybuffer";
717 
718         xhr.onload = function () {
719             var arrayBuffer = xhr.response; // Note: not oReq.responseText
720             if (arrayBuffer) {
721                 window.msg = arrayBuffer;
722             }
723             if(xhr.readyState === 4)
724                 xhr.status === 200 ? cb(null, xhr.response) : cb("load " + url + " failed!");
725         };
726 
727         xhr.send(null);
728     },
729 
730     /**
731      * Load a single resource as json.
732      * @param {string} url
733      * @param {function} [cb] arguments are : err, json
734      */
735     loadJson: function (url, cb) {
736         this.loadTxt(url, function (err, txt) {
737             if (err) {
738                 cb(err);
739             }
740             else {
741                 try {
742                     var result = JSON.parse(txt);
743                 }
744                 catch (e) {
745                     throw "parse json [" + url + "] failed : " + e;
746                     return;
747                 }
748                 cb(null, result);
749             }
750         });
751     },
752 
753     _checkIsImageURL: function (url) {
754         var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url);
755         return (ext != null);
756     },
757     /**
758      * Load a single image.
759      * @param {!string} url
760      * @param {object} [option]
761      * @param {function} callback
762      * @returns {Image}
763      */
764     loadImg: function (url, option, callback) {
765         var opt = {
766             isCrossOrigin: true
767         };
768         if (callback !== undefined)
769             opt.isCrossOrigin = option.isCrossOrigin === null ? opt.isCrossOrigin : option.isCrossOrigin;
770         else if (option !== undefined)
771             callback = option;
772 
773         var img = this.getRes(url);
774         if (img) {
775             callback && callback(null, img);
776             return img;
777         }
778 
779         img = new Image();
780         if (opt.isCrossOrigin && location.origin !== "file://")
781             img.crossOrigin = "Anonymous";
782 
783         var loadCallback = function () {
784             this.removeEventListener('load', loadCallback, false);
785             this.removeEventListener('error', errorCallback, false);
786 
787             cc.loader.cache[url] = img;
788             if (callback)
789                 callback(null, img);
790         };
791 
792         var self = this;
793         var errorCallback = function () {
794             this.removeEventListener('error', errorCallback, false);
795 
796             if(img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous"){
797                 opt.isCrossOrigin = false;
798                 self.release(url);
799                 cc.loader.loadImg(url, opt, callback);
800             }else{
801                 typeof callback === "function" && callback("load image failed");
802             }
803         };
804 
805         cc._addEventListener(img, "load", loadCallback);
806         cc._addEventListener(img, "error", errorCallback);
807         img.src = url;
808         return img;
809     },
810 
811     /**
812      * Iterator function to load res
813      * @param {object} item
814      * @param {number} index
815      * @param {function} [cb]
816      * @returns {*}
817      * @private
818      */
819     _loadResIterator: function (item, index, cb) {
820         var self = this, url = null;
821         var type = item.type;
822         if (type) {
823             type = "." + type.toLowerCase();
824             url = item.src ? item.src : item.name + type;
825         } else {
826             url = item;
827             type = cc.path.extname(url);
828         }
829 
830         var obj = self.getRes(url);
831         if (obj)
832             return cb(null, obj);
833         var loader = null;
834         if (type) {
835             loader = self._register[type.toLowerCase()];
836         }
837         if (!loader) {
838             cc.error("loader for [" + type + "] not exists!");
839             return cb();
840         }
841         var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
842         var realUrl = self.getUrl(basePath, url);
843         if(cc.game.config["noCache"] && typeof realUrl === "string"){
844             if(self._noCacheRex.test(realUrl))
845                 realUrl += "&_t=" + (new Date() - 0);
846             else
847                 realUrl += "?_t=" + (new Date() - 0);
848         }
849         loader.load(realUrl, url, item, function (err, data) {
850             if (err) {
851                 cc.log(err);
852                 self.cache[url] = null;
853                 delete self.cache[url];
854                 cb();
855             } else {
856                 self.cache[url] = data;
857                 cb(null, data);
858             }
859         });
860     },
861     _noCacheRex: /\?/,
862 
863     /**
864      * Get url with basePath.
865      * @param {string} basePath
866      * @param {string} [url]
867      * @returns {*}
868      */
869     getUrl: function (basePath, url) {
870         var self = this, langPathCache = self._langPathCache, path = cc.path;
871         if (basePath !== undefined && url === undefined) {
872             url = basePath;
873             var type = path.extname(url);
874             type = type ? type.toLowerCase() : "";
875             var loader = self._register[type];
876             if (!loader)
877                 basePath = self.resPath;
878             else
879                 basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
880         }
881         url = cc.path.join(basePath || "", url);
882         if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) {
883             if (langPathCache[url])
884                 return langPathCache[url];
885             var extname = path.extname(url) || "";
886             url = langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname;
887         }
888         return url;
889     },
890 
891     /**
892      * Load resources then call the callback.
893      * @param {string} resources
894      * @param {function} [option] callback or trigger
895      * @param {function|Object} [loadCallback]
896      * @return {cc.AsyncPool}
897      */
898     load : function(resources, option, loadCallback){
899         var self = this;
900         var len = arguments.length;
901         if(len === 0)
902             throw "arguments error!";
903 
904         if(len === 3){
905             if(typeof option === "function"){
906                 if(typeof loadCallback === "function")
907                     option = {trigger : option, cb : loadCallback };
908                 else
909                     option = { cb : option, cbTarget : loadCallback};
910             }
911         }else if(len === 2){
912             if(typeof option === "function")
913                 option = {cb : option};
914         }else if(len === 1){
915             option = {};
916         }
917 
918         if(!(resources instanceof Array))
919             resources = [resources];
920         var asyncPool = new cc.AsyncPool(
921             resources, 0,
922             function (value, index, AsyncPoolCallback, aPool) {
923                 self._loadResIterator(value, index, function (err) {
924                     if (err)
925                         return AsyncPoolCallback(err);
926                     var arr = Array.prototype.slice.call(arguments, 1);
927                     if (option.trigger)
928                         option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize);   //call trigger
929                     AsyncPoolCallback(null, arr[0]);
930                 });
931             },
932             option.cb, option.cbTarget);
933         asyncPool.flow();
934         return asyncPool;
935     },
936 
937     _handleAliases: function (fileNames, cb) {
938         var self = this, aliases = self._aliases;
939         var resList = [];
940         for (var key in fileNames) {
941             var value = fileNames[key];
942             aliases[key] = value;
943             resList.push(value);
944         }
945         this.load(resList, cb);
946     },
947 
948     /**
949      * <p>
950      *     Loads alias map from the contents of a filename.                                        <br/>
951      *                                                                                                                 <br/>
952      *     @note The plist file name should follow the format below:                                                   <br/>
953      *     <?xml version="1.0" encoding="UTF-8"?>                                                                      <br/>
954      *         <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  <br/>
955      *             <plist version="1.0">                                                                               <br/>
956      *                 <dict>                                                                                          <br/>
957      *                     <key>filenames</key>                                                                        <br/>
958      *                     <dict>                                                                                      <br/>
959      *                         <key>sounds/click.wav</key>                                                             <br/>
960      *                         <string>sounds/click.caf</string>                                                       <br/>
961      *                         <key>sounds/endgame.wav</key>                                                           <br/>
962      *                         <string>sounds/endgame.caf</string>                                                     <br/>
963      *                         <key>sounds/gem-0.wav</key>                                                             <br/>
964      *                         <string>sounds/gem-0.caf</string>                                                       <br/>
965      *                     </dict>                                                                                     <br/>
966      *                     <key>metadata</key>                                                                         <br/>
967      *                     <dict>                                                                                      <br/>
968      *                         <key>version</key>                                                                      <br/>
969      *                         <integer>1</integer>                                                                    <br/>
970      *                     </dict>                                                                                     <br/>
971      *                 </dict>                                                                                         <br/>
972      *              </plist>                                                                                           <br/>
973      * </p>
974      * @param {String} url  The plist file name.
975      * @param {Function} [callback]
976      */
977     loadAliases: function (url, callback) {
978         var self = this, dict = self.getRes(url);
979         if (!dict) {
980             self.load(url, function (err, results) {
981                 self._handleAliases(results[0]["filenames"], callback);
982             });
983         } else
984             self._handleAliases(dict["filenames"], callback);
985     },
986 
987     /**
988      * Register a resource loader into loader.
989      * @param {string} extNames
990      * @param {function} loader
991      */
992     register: function (extNames, loader) {
993         if (!extNames || !loader) return;
994         var self = this;
995         if (typeof extNames === "string")
996             return this._register[extNames.trim().toLowerCase()] = loader;
997         for (var i = 0, li = extNames.length; i < li; i++) {
998             self._register["." + extNames[i].trim().toLowerCase()] = loader;
999         }
1000     },
1001 
1002     /**
1003      * Get resource data by url.
1004      * @param url
1005      * @returns {*}
1006      */
1007     getRes: function (url) {
1008         return this.cache[url] || this.cache[this._aliases[url]];
1009     },
1010 
1011     /**
1012      * Release the cache of resource by url.
1013      * @param url
1014      */
1015     release: function (url) {
1016         var cache = this.cache, aliases = this._aliases;
1017         delete cache[url];
1018         delete cache[aliases[url]];
1019         delete aliases[url];
1020     },
1021 
1022     /**
1023      * Resource cache of all resources.
1024      */
1025     releaseAll: function () {
1026         var locCache = this.cache, aliases = this._aliases;
1027         for (var key in locCache)
1028             delete locCache[key];
1029         for (var key in aliases)
1030             delete aliases[key];
1031     }
1032 };
1033 //+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++
1034 
1035 /**
1036  * A string tool to construct a string with format string.
1037  * for example:
1038  *      cc.formatStr("a: %d, b: %b", a, b);
1039  *      cc.formatStr(a, b, c);
1040  * @returns {String}
1041  */
1042 cc.formatStr = function(){
1043     var args = arguments;
1044     var l = args.length;
1045     if(l < 1)
1046         return "";
1047 
1048     var str = args[0];
1049     var needToFormat = true;
1050     if(typeof str === "object"){
1051         needToFormat = false;
1052     }
1053     for(var i = 1; i < l; ++i){
1054         var arg = args[i];
1055         if(needToFormat){
1056             while(true){
1057                 var result = null;
1058                 if(typeof arg === "number"){
1059                     result = str.match(/(%d)|(%s)/);
1060                     if(result){
1061                         str = str.replace(/(%d)|(%s)/, arg);
1062                         break;
1063                     }
1064                 }
1065                 result = str.match(/%s/);
1066                 if(result)
1067                     str = str.replace(/%s/, arg);
1068                 else
1069                     str += "    " + arg;
1070                 break;
1071             }
1072         }else
1073             str += "    " + arg;
1074     }
1075     return str;
1076 };
1077 
1078 
1079 //+++++++++++++++++++++++++something about window events begin+++++++++++++++++++++++++++
1080 (function () {
1081     var win = window, hidden, visibilityChange, _undef = "undefined";
1082     if (!cc.isUndefined(document.hidden)) {
1083         hidden = "hidden";
1084         visibilityChange = "visibilitychange";
1085     } else if (!cc.isUndefined(document.mozHidden)) {
1086         hidden = "mozHidden";
1087         visibilityChange = "mozvisibilitychange";
1088     } else if (!cc.isUndefined(document.msHidden)) {
1089         hidden = "msHidden";
1090         visibilityChange = "msvisibilitychange";
1091     } else if (!cc.isUndefined(document.webkitHidden)) {
1092         hidden = "webkitHidden";
1093         visibilityChange = "webkitvisibilitychange";
1094     }
1095 
1096     var onHidden = function () {
1097         if (cc.eventManager && cc.game._eventHide)
1098             cc.eventManager.dispatchEvent(cc.game._eventHide);
1099     };
1100     var onShow = function () {
1101         if (cc.eventManager && cc.game._eventShow)
1102             cc.eventManager.dispatchEvent(cc.game._eventShow);
1103 
1104         if(cc.game._intervalId){
1105             window.cancelAnimationFrame(cc.game._intervalId);
1106 
1107             cc.game._runMainLoop();
1108         }
1109     };
1110 
1111     if (hidden) {
1112         cc._addEventListener(document, visibilityChange, function () {
1113             if (document[hidden]) onHidden();
1114             else onShow();
1115         }, false);
1116     } else {
1117         cc._addEventListener(win, "blur", onHidden, false);
1118         cc._addEventListener(win, "focus", onShow, false);
1119     }
1120 
1121     if(navigator.userAgent.indexOf("MicroMessenger") > -1){
1122         win.onfocus = function(){ onShow() };
1123     }
1124 
1125     if ("onpageshow" in window && "onpagehide" in window) {
1126         cc._addEventListener(win, "pagehide", onHidden, false);
1127         cc._addEventListener(win, "pageshow", onShow, false);
1128     }
1129     win = null;
1130     visibilityChange = null;
1131 })();
1132 //+++++++++++++++++++++++++something about window events end+++++++++++++++++++++++++++++
1133 
1134 //+++++++++++++++++++++++++something about log start++++++++++++++++++++++++++++
1135 
1136 //to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode.
1137 
1138 cc.log = cc.warn = cc.error = cc.assert = function () {
1139 };
1140 
1141 //+++++++++++++++++++++++++something about log end+++++++++++++++++++++++++++++
1142 
1143 /**
1144  * create a webgl context
1145  * @param {HTMLCanvasElement} canvas
1146  * @param {Object} opt_attribs
1147  * @return {WebGLRenderingContext}
1148  */
1149 cc.create3DContext = function (canvas, opt_attribs) {
1150     var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
1151     var context = null;
1152     for (var ii = 0; ii < names.length; ++ii) {
1153         try {
1154             context = canvas.getContext(names[ii], opt_attribs);
1155         } catch (e) {
1156         }
1157         if (context) {
1158             break;
1159         }
1160     }
1161     return context;
1162 };
1163 //+++++++++++++++++++++++++something about sys begin+++++++++++++++++++++++++++++
1164 cc._initSys = function (config, CONFIG_KEY) {
1165     /**
1166      * Canvas of render type
1167      * @constant
1168      * @type {Number}
1169      */
1170     cc._RENDER_TYPE_CANVAS = 0;
1171 
1172     /**
1173      * WebGL of render type
1174      * @constant
1175      * @type {Number}
1176      */
1177     cc._RENDER_TYPE_WEBGL = 1;
1178 
1179     /**
1180      * System variables
1181      * @namespace
1182      * @name cc.sys
1183      */
1184     cc.sys = {};
1185     var sys = cc.sys;
1186 
1187     /**
1188      * English language code
1189      * @memberof cc.sys
1190      * @name LANGUAGE_ENGLISH
1191      * @constant
1192      * @type {Number}
1193      */
1194     sys.LANGUAGE_ENGLISH = "en";
1195 
1196     /**
1197      * Chinese language code
1198      * @memberof cc.sys
1199      * @name LANGUAGE_CHINESE
1200      * @constant
1201      * @type {Number}
1202      */
1203     sys.LANGUAGE_CHINESE = "zh";
1204 
1205     /**
1206      * French language code
1207      * @memberof cc.sys
1208      * @name LANGUAGE_FRENCH
1209      * @constant
1210      * @type {Number}
1211      */
1212     sys.LANGUAGE_FRENCH = "fr";
1213 
1214     /**
1215      * Italian language code
1216      * @memberof cc.sys
1217      * @name LANGUAGE_ITALIAN
1218      * @constant
1219      * @type {Number}
1220      */
1221     sys.LANGUAGE_ITALIAN = "it";
1222 
1223     /**
1224      * German language code
1225      * @memberof cc.sys
1226      * @name LANGUAGE_GERMAN
1227      * @constant
1228      * @type {Number}
1229      */
1230     sys.LANGUAGE_GERMAN = "de";
1231 
1232     /**
1233      * Spanish language code
1234      * @memberof cc.sys
1235      * @name LANGUAGE_SPANISH
1236      * @constant
1237      * @type {Number}
1238      */
1239     sys.LANGUAGE_SPANISH = "es";
1240 
1241     /**
1242      * Spanish language code
1243      * @memberof cc.sys
1244      * @name LANGUAGE_DUTCH
1245      * @constant
1246      * @type {Number}
1247      */
1248     sys.LANGUAGE_DUTCH = "du";
1249 
1250     /**
1251      * Russian language code
1252      * @memberof cc.sys
1253      * @name LANGUAGE_RUSSIAN
1254      * @constant
1255      * @type {Number}
1256      */
1257     sys.LANGUAGE_RUSSIAN = "ru";
1258 
1259     /**
1260      * Korean language code
1261      * @memberof cc.sys
1262      * @name LANGUAGE_KOREAN
1263      * @constant
1264      * @type {Number}
1265      */
1266     sys.LANGUAGE_KOREAN = "ko";
1267 
1268     /**
1269      * Japanese language code
1270      * @memberof cc.sys
1271      * @name LANGUAGE_JAPANESE
1272      * @constant
1273      * @type {Number}
1274      */
1275     sys.LANGUAGE_JAPANESE = "ja";
1276 
1277     /**
1278      * Hungarian language code
1279      * @memberof cc.sys
1280      * @name LANGUAGE_HUNGARIAN
1281      * @constant
1282      * @type {Number}
1283      */
1284     sys.LANGUAGE_HUNGARIAN = "hu";
1285 
1286     /**
1287      * Portuguese language code
1288      * @memberof cc.sys
1289      * @name LANGUAGE_PORTUGUESE
1290      * @constant
1291      * @type {Number}
1292      */
1293     sys.LANGUAGE_PORTUGUESE = "pt";
1294 
1295     /**
1296      * Arabic language code
1297      * @memberof cc.sys
1298      * @name LANGUAGE_ARABIC
1299      * @constant
1300      * @type {Number}
1301      */
1302     sys.LANGUAGE_ARABIC = "ar";
1303 
1304     /**
1305      * Norwegian language code
1306      * @memberof cc.sys
1307      * @name LANGUAGE_NORWEGIAN
1308      * @constant
1309      * @type {Number}
1310      */
1311     sys.LANGUAGE_NORWEGIAN = "no";
1312 
1313     /**
1314      * Polish language code
1315      * @memberof cc.sys
1316      * @name LANGUAGE_POLISH
1317      * @constant
1318      * @type {Number}
1319      */
1320     sys.LANGUAGE_POLISH = "pl";
1321 
1322     /**
1323      * @memberof cc.sys
1324      * @name OS_IOS
1325      * @constant
1326      * @type {string}
1327      */
1328     sys.OS_IOS = "iOS";
1329     /**
1330      * @memberof cc.sys
1331      * @name OS_ANDROID
1332      * @constant
1333      * @type {string}
1334      */
1335     sys.OS_ANDROID = "Android";
1336     /**
1337      * @memberof cc.sys
1338      * @name OS_WINDOWS
1339      * @constant
1340      * @type {string}
1341      */
1342     sys.OS_WINDOWS = "Windows";
1343     /**
1344      * @memberof cc.sys
1345      * @name OS_MARMALADE
1346      * @constant
1347      * @type {string}
1348      */
1349     sys.OS_MARMALADE = "Marmalade";
1350     /**
1351      * @memberof cc.sys
1352      * @name OS_LINUX
1353      * @constant
1354      * @type {string}
1355      */
1356     sys.OS_LINUX = "Linux";
1357     /**
1358      * @memberof cc.sys
1359      * @name OS_BADA
1360      * @constant
1361      * @type {string}
1362      */
1363     sys.OS_BADA = "Bada";
1364     /**
1365      * @memberof cc.sys
1366      * @name OS_BLACKBERRY
1367      * @constant
1368      * @type {string}
1369      */
1370     sys.OS_BLACKBERRY = "Blackberry";
1371     /**
1372      * @memberof cc.sys
1373      * @name OS_OSX
1374      * @constant
1375      * @type {string}
1376      */
1377     sys.OS_OSX = "OS X";
1378     /**
1379      * @memberof cc.sys
1380      * @name OS_WP8
1381      * @constant
1382      * @type {string}
1383      */
1384     sys.OS_WP8 = "WP8";
1385     /**
1386      * @memberof cc.sys
1387      * @name OS_WINRT
1388      * @constant
1389      * @type {string}
1390      */
1391     sys.OS_WINRT = "WINRT";
1392     /**
1393      * @memberof cc.sys
1394      * @name OS_UNKNOWN
1395      * @constant
1396      * @type {string}
1397      */
1398     sys.OS_UNKNOWN = "Unknown";
1399 
1400     /**
1401      * @memberof cc.sys
1402      * @name UNKNOWN
1403      * @constant
1404      * @default
1405      * @type {Number}
1406      */
1407     sys.UNKNOWN = 0;
1408     /**
1409      * @memberof cc.sys
1410      * @name IOS
1411      * @constant
1412      * @default
1413      * @type {Number}
1414      */
1415     sys.IOS = 1;
1416     /**
1417      * @memberof cc.sys
1418      * @name ANDROID
1419      * @constant
1420      * @default
1421      * @type {Number}
1422      */
1423     sys.ANDROID = 2;
1424     /**
1425      * @memberof cc.sys
1426      * @name WIN32
1427      * @constant
1428      * @default
1429      * @type {Number}
1430      */
1431     sys.WIN32 = 3;
1432     /**
1433      * @memberof cc.sys
1434      * @name MARMALADE
1435      * @constant
1436      * @default
1437      * @type {Number}
1438      */
1439     sys.MARMALADE = 4;
1440     /**
1441      * @memberof cc.sys
1442      * @name LINUX
1443      * @constant
1444      * @default
1445      * @type {Number}
1446      */
1447     sys.LINUX = 5;
1448     /**
1449      * @memberof cc.sys
1450      * @name BADA
1451      * @constant
1452      * @default
1453      * @type {Number}
1454      */
1455     sys.BADA = 6;
1456     /**
1457      * @memberof cc.sys
1458      * @name BLACKBERRY
1459      * @constant
1460      * @default
1461      * @type {Number}
1462      */
1463     sys.BLACKBERRY = 7;
1464     /**
1465      * @memberof cc.sys
1466      * @name MACOS
1467      * @constant
1468      * @default
1469      * @type {Number}
1470      */
1471     sys.MACOS = 8;
1472     /**
1473      * @memberof cc.sys
1474      * @name NACL
1475      * @constant
1476      * @default
1477      * @type {Number}
1478      */
1479     sys.NACL = 9;
1480     /**
1481      * @memberof cc.sys
1482      * @name EMSCRIPTEN
1483      * @constant
1484      * @default
1485      * @type {Number}
1486      */
1487     sys.EMSCRIPTEN = 10;
1488     /**
1489      * @memberof cc.sys
1490      * @name TIZEN
1491      * @constant
1492      * @default
1493      * @type {Number}
1494      */
1495     sys.TIZEN = 11;
1496     /**
1497      * @memberof cc.sys
1498      * @name QT5
1499      * @constant
1500      * @default
1501      * @type {Number}
1502      */
1503     sys.QT5 = 12;
1504     /**
1505      * @memberof cc.sys
1506      * @name WP8
1507      * @constant
1508      * @default
1509      * @type {Number}
1510      */
1511     sys.WP8 = 13;
1512     /**
1513      * @memberof cc.sys
1514      * @name WINRT
1515      * @constant
1516      * @default
1517      * @type {Number}
1518      */
1519     sys.WINRT = 14;
1520     /**
1521      * @memberof cc.sys
1522      * @name MOBILE_BROWSER
1523      * @constant
1524      * @default
1525      * @type {Number}
1526      */
1527     sys.MOBILE_BROWSER = 100;
1528     /**
1529      * @memberof cc.sys
1530      * @name DESKTOP_BROWSER
1531      * @constant
1532      * @default
1533      * @type {Number}
1534      */
1535     sys.DESKTOP_BROWSER = 101;
1536 
1537     sys.BROWSER_TYPE_WECHAT = "wechat";
1538     sys.BROWSER_TYPE_ANDROID = "androidbrowser";
1539     sys.BROWSER_TYPE_IE = "ie";
1540     sys.BROWSER_TYPE_QQ = "qqbrowser";
1541     sys.BROWSER_TYPE_MOBILE_QQ = "mqqbrowser";
1542     sys.BROWSER_TYPE_UC = "ucbrowser";
1543     sys.BROWSER_TYPE_360 = "360browser";
1544     sys.BROWSER_TYPE_BAIDU_APP = "baiduboxapp";
1545     sys.BROWSER_TYPE_BAIDU = "baidubrowser";
1546     sys.BROWSER_TYPE_MAXTHON = "maxthon";
1547     sys.BROWSER_TYPE_OPERA = "opera";
1548     sys.BROWSER_TYPE_OUPENG = "oupeng";
1549     sys.BROWSER_TYPE_MIUI = "miuibrowser";
1550     sys.BROWSER_TYPE_FIREFOX = "firefox";
1551     sys.BROWSER_TYPE_SAFARI = "safari";
1552     sys.BROWSER_TYPE_CHROME = "chrome";
1553     sys.BROWSER_TYPE_LIEBAO = "liebao";
1554     sys.BROWSER_TYPE_QZONE = "qzone";
1555     sys.BROWSER_TYPE_SOUGOU = "sogou";
1556     sys.BROWSER_TYPE_UNKNOWN = "unknown";
1557 
1558     /**
1559      * Is native ? This is set to be true in jsb auto.
1560      * @memberof cc.sys
1561      * @name isNative
1562      * @type {Boolean}
1563      */
1564     sys.isNative = false;
1565 
1566     var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement;
1567     var ua = nav.userAgent.toLowerCase();
1568 
1569     /**
1570      * Indicate whether system is mobile system
1571      * @memberof cc.sys
1572      * @name isMobile
1573      * @type {Boolean}
1574      */
1575     sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1;
1576 
1577     /**
1578      * Indicate the running platform
1579      * @memberof cc.sys
1580      * @name platform
1581      * @type {Number}
1582      */
1583     sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER;
1584 
1585     var currLanguage = nav.language;
1586     currLanguage = currLanguage ? currLanguage : nav.browserLanguage;
1587     currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH;
1588 
1589     /**
1590      * Indicate the current language of the running system
1591      * @memberof cc.sys
1592      * @name language
1593      * @type {String}
1594      */
1595     sys.language = currLanguage;
1596 
1597     var browserType = sys.BROWSER_TYPE_UNKNOWN;
1598     var browserTypes = ua.match(/sogou|qzone|liebao|micromessenger|qqbrowser|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i)
1599         || ua.match(/chrome|safari/i);
1600     if (browserTypes && browserTypes.length > 0) {
1601         browserType = browserTypes[0];
1602         if (browserType === 'micromessenger') {
1603             browserType = sys.BROWSER_TYPE_WECHAT;
1604         } else if (browserType === "safari" && (ua.match(/android.*applewebkit/)))
1605             browserType = sys.BROWSER_TYPE_ANDROID;
1606         else if (browserType === "trident") browserType = sys.BROWSER_TYPE_IE;
1607         else if (browserType === "360 aphone") browserType = sys.BROWSER_TYPE_360;
1608     }else if(ua.indexOf("iphone") && ua.indexOf("mobile")){
1609         browserType = "safari";
1610     }
1611     /**
1612      * Indicate the running browser type
1613      * @memberof cc.sys
1614      * @name browserType
1615      * @type {String}
1616      */
1617     sys.browserType = browserType;
1618 
1619     // Get the os of system
1620     var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false );
1621     var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false;
1622     var osName = sys.OS_UNKNOWN;
1623     if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS;
1624     else if (iOS) osName = sys.OS_IOS;
1625     else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX;
1626     else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX;
1627     else if (isAndroid) osName = sys.OS_ANDROID;
1628     else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX;
1629 
1630     /**
1631      * Indicate the running os name
1632      * @memberof cc.sys
1633      * @name os
1634      * @type {String}
1635      */
1636     sys.os = osName;
1637 
1638     var multipleAudioWhiteList = [
1639         sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP,
1640         sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE
1641     ];
1642 
1643     sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1;
1644 
1645 
1646     //++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++
1647 
1648     (function(sys, config){
1649         var userRenderMode = config[CONFIG_KEY.renderMode] - 0;
1650         if(isNaN(userRenderMode) || userRenderMode > 2 || userRenderMode < 0)
1651             userRenderMode = 0;
1652         var shieldOs = [sys.OS_ANDROID];
1653         var shieldBrowser = [];
1654         var tmpCanvas = cc.newElement("canvas");
1655         cc._renderType = cc._RENDER_TYPE_CANVAS;
1656         cc._supportRender = false;
1657 
1658         var supportWebGL = win.WebGLRenderingContext;
1659 
1660         if(userRenderMode === 2 || (userRenderMode === 0 && supportWebGL && shieldOs.indexOf(sys.os) === -1 && shieldBrowser.indexOf(sys.browserType) === -1))
1661             try{
1662                 var context = cc.create3DContext(tmpCanvas, {'stencil': true, 'preserveDrawingBuffer': true });
1663                 if(context){
1664                     cc._renderType = cc._RENDER_TYPE_WEBGL;
1665                     cc._supportRender = true;
1666                 }
1667             }catch(e){}
1668 
1669         if(userRenderMode === 1 || (userRenderMode === 0 && cc._supportRender === false))
1670             try {
1671                 tmpCanvas.getContext("2d");
1672                 cc._renderType = cc._RENDER_TYPE_CANVAS;
1673                 cc._supportRender = true;
1674             } catch (e) {}
1675     })(sys, config);
1676 
1677     sys._canUseCanvasNewBlendModes = function(){
1678         var canvas = document.createElement('canvas');
1679         canvas.width = 1;
1680         canvas.height = 1;
1681         var context = canvas.getContext('2d');
1682         context.fillStyle = '#000';
1683         context.fillRect(0,0,1,1);
1684         context.globalCompositeOperation = 'multiply';
1685 
1686         var canvas2 = document.createElement('canvas');
1687         canvas2.width = 1;
1688         canvas2.height = 1;
1689         var context2 = canvas2.getContext('2d');
1690         context2.fillStyle = '#fff';
1691         context2.fillRect(0,0,1,1);
1692 
1693         context.drawImage(canvas2, 0, 0, 1, 1);
1694 
1695         return context.getImageData(0,0,1,1).data[0] === 0;
1696     };
1697 
1698     //Whether or not the Canvas BlendModes are supported.
1699     sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes();
1700 
1701     //++++++++++++++++++something about cc._renderType and cc._supportRender end++++++++++++++++++++++++++++++
1702 
1703     // check if browser supports Web Audio
1704     // check Web Audio's context
1705     try {
1706         sys._supportWebAudio = !!(win.AudioContext || win.webkitAudioContext || win.mozAudioContext);
1707     } catch (e) {
1708         sys._supportWebAudio = false;
1709     }
1710 
1711     /**
1712      * cc.sys.localStorage is a local storage component.
1713      * @memberof cc.sys
1714      * @name localStorage
1715      * @type {Object}
1716      */
1717     try {
1718         var localStorage = sys.localStorage = win.localStorage;
1719         localStorage.setItem("storage", "");
1720         localStorage.removeItem("storage");
1721         localStorage = null;
1722     } catch (e) {
1723         if (e.name === "SECURITY_ERR" || e.name === "QuotaExceededError") {
1724             cc.warn("Warning: localStorage isn't enabled. Please confirm browser cookie or privacy option");
1725         }
1726         sys.localStorage = function () {
1727         };
1728     }
1729 
1730     var capabilities = sys.capabilities = {"canvas": true};
1731     if (cc._renderType === cc._RENDER_TYPE_WEBGL)
1732         capabilities["opengl"] = true;
1733     if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled)
1734         capabilities["touches"] = true;
1735     if (docEle['onmouseup'] !== undefined)
1736         capabilities["mouse"] = true;
1737     if (docEle['onkeyup'] !== undefined)
1738         capabilities["keyboard"] = true;
1739     if (win.DeviceMotionEvent || win.DeviceOrientationEvent)
1740         capabilities["accelerometer"] = true;
1741 
1742     /**
1743      * Forces the garbage collection, only available in JSB
1744      * @memberof cc.sys
1745      * @name garbageCollect
1746      * @function
1747      */
1748     sys.garbageCollect = function () {
1749         // N/A in cocos2d-html5
1750     };
1751 
1752     /**
1753      * Dumps rooted objects, only available in JSB
1754      * @memberof cc.sys
1755      * @name dumpRoot
1756      * @function
1757      */
1758     sys.dumpRoot = function () {
1759         // N/A in cocos2d-html5
1760     };
1761 
1762     /**
1763      * Restart the JS VM, only available in JSB
1764      * @memberof cc.sys
1765      * @name restartVM
1766      * @function
1767      */
1768     sys.restartVM = function () {
1769         // N/A in cocos2d-html5
1770     };
1771 
1772     /**
1773      * Clean a script in the JS VM, only available in JSB
1774      * @memberof cc.sys
1775      * @name cleanScript
1776      * @param {String} jsfile
1777      * @function
1778      */
1779     sys.cleanScript = function (jsfile) {
1780         // N/A in cocos2d-html5
1781     };
1782 
1783     /**
1784      * Check whether an object is valid,
1785      * In web engine, it will return true if the object exist
1786      * In native engine, it will return true if the JS object and the correspond native object are both valid
1787      * @memberof cc.sys
1788      * @name isObjectValid
1789      * @param {Object} obj
1790      * @return {boolean} Validity of the object
1791      * @function
1792      */
1793     sys.isObjectValid = function (obj) {
1794         if (obj) return true;
1795         else return false;
1796     };
1797 
1798     /**
1799      * Dump system informations
1800      * @memberof cc.sys
1801      * @name dump
1802      * @function
1803      */
1804     sys.dump = function () {
1805         var self = this;
1806         var str = "";
1807         str += "isMobile : " + self.isMobile + "\r\n";
1808         str += "language : " + self.language + "\r\n";
1809         str += "browserType : " + self.browserType + "\r\n";
1810         str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n";
1811         str += "os : " + self.os + "\r\n";
1812         str += "platform : " + self.platform + "\r\n";
1813         cc.log(str);
1814     }
1815 
1816     /**
1817      * Open a url in browser
1818      * @memberof cc.sys
1819      * @name openURL
1820      * @param {String} url
1821      */
1822     sys.openURL = function(url){
1823         window.open(url);
1824     }
1825 };
1826 
1827 //+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++
1828 
1829 //+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++
1830 
1831 /**
1832  * Device oriented vertically, home button on the bottom
1833  * @constant
1834  * @type {Number}
1835  */
1836 cc.ORIENTATION_PORTRAIT = 0;
1837 
1838 /**
1839  * Device oriented vertically, home button on the top
1840  * @constant
1841  * @type {Number}
1842  */
1843 cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1;
1844 
1845 /**
1846  * Device oriented horizontally, home button on the right
1847  * @constant
1848  * @type {Number}
1849  */
1850 cc.ORIENTATION_LANDSCAPE_LEFT = 2;
1851 
1852 /**
1853  * Device oriented horizontally, home button on the left
1854  * @constant
1855  * @type {Number}
1856  */
1857 cc.ORIENTATION_LANDSCAPE_RIGHT = 3;
1858 
1859 /**
1860  * drawing primitive of game engine
1861  * @type {cc.DrawingPrimitive}
1862  */
1863 cc._drawingUtil = null;
1864 
1865 /**
1866  * main Canvas 2D/3D Context of game engine
1867  * @type {CanvasRenderingContext2D|WebGLRenderingContext}
1868  */
1869 cc._renderContext = null;
1870 
1871 /**
1872  * main Canvas of game engine
1873  * @type {HTMLCanvasElement}
1874  */
1875 cc._canvas = null;
1876 
1877 /**
1878  * This Div element contain all game canvas
1879  * @type {HTMLDivElement}
1880  */
1881 cc._gameDiv = null;
1882 
1883 cc._rendererInitialized = false;
1884 /**
1885  * <p>
1886  *   setup game main canvas,renderContext,gameDiv and drawingUtil with argument  <br/>
1887  *   <br/>
1888  *   can receive follow type of arguemnt: <br/>
1889  *      - empty: create a canvas append to document's body, and setup other option    <br/>
1890  *      - string: search the element by document.getElementById(),    <br/>
1891  *          if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc._gameDiv.<br/>
1892  *          if this element is HTMLDivElement, set it's ParentNode to cc._gameDiv´╝î and create a canvas as main canvas of engine.   <br/>
1893  * </p>
1894  * @function
1895  * @example
1896  * //setup with null
1897  * cc._setup();
1898  *
1899  * // setup with HTMLCanvasElement, gameCanvas is Canvas element
1900  * // declare like this: <canvas id="gameCanvas" width="800" height="450"></canvas>
1901  * cc._setup("gameCanvas");
1902  *
1903  * //setup with HTMLDivElement, gameDiv is Div element
1904  * // declare like this: <div id="Cocos2dGameContainer" width="800" height="450"></div>
1905  * cc._setup("Cocos2dGameContainer");
1906  */
1907 cc._setupCalled = false;
1908 cc._setup = function (el, width, height) {
1909     // Avoid setup to be called twice.
1910     if (cc._setupCalled) return;
1911     else cc._setupCalled = true;
1912     var win = window;
1913     var element = cc.$(el) || cc.$('#' + el);
1914     var localCanvas, localContainer, localConStyle;
1915 
1916     cc.game._setAnimFrame();
1917 
1918     if (element.tagName === "CANVAS") {
1919         width = width || element.width;
1920         height = height || element.height;
1921 
1922         //it is already a canvas, we wrap it around with a div
1923         localContainer = cc.container = cc.newElement("DIV");
1924         localCanvas = cc._canvas = element;
1925         localCanvas.parentNode.insertBefore(localContainer, localCanvas);
1926         localCanvas.appendTo(localContainer);
1927         localContainer.setAttribute('id', 'Cocos2dGameContainer');
1928     } else {//we must make a new canvas and place into this element
1929         if (element.tagName !== "DIV") {
1930             cc.log("Warning: target element is not a DIV or CANVAS");
1931         }
1932         width = width || element.clientWidth;
1933         height = height || element.clientHeight;
1934         localContainer = cc.container = element;
1935         localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS"));
1936         element.appendChild(localCanvas);
1937     }
1938 
1939     localCanvas.addClass("gameCanvas");
1940     localCanvas.setAttribute("width", width || 480);
1941     localCanvas.setAttribute("height", height || 320);
1942     localCanvas.setAttribute("tabindex", 99);
1943     localCanvas.style.outline = "none";
1944     localConStyle = localContainer.style;
1945     localConStyle.width = (width || 480) + "px";
1946     localConStyle.height = (height || 320) + "px";
1947     localConStyle.margin = "0 auto";
1948 
1949     localConStyle.position = 'relative';
1950     localConStyle.overflow = 'hidden';
1951     localContainer.top = '100%';
1952 
1953     if (cc._renderType === cc._RENDER_TYPE_WEBGL)
1954         cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, {
1955             'stencil': true,
1956             'preserveDrawingBuffer': true,
1957             'antialias': !cc.sys.isMobile,
1958             'alpha': false
1959         });
1960     if (cc._renderContext) {
1961         win.gl = cc._renderContext; // global variable declared in CCMacro.js
1962         cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext);
1963         cc._rendererInitialized = true;
1964         cc.textureCache._initializingRenderer();
1965         cc.shaderCache._init();
1966     } else {
1967         cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d"));
1968         cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null;
1969     }
1970 
1971     cc._gameDiv = localContainer;
1972     cc.log(cc.ENGINE_VERSION);
1973     cc._setContextMenuEnable(false);
1974 
1975     if (cc.sys.isMobile) {
1976         var fontStyle = cc.newElement("style");
1977         fontStyle.type = "text/css";
1978         document.body.appendChild(fontStyle);
1979 
1980         fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;"
1981             + "-webkit-tap-highlight-color:rgba(0,0,0,0);}";
1982     }
1983 
1984     // Init singletons
1985 
1986     /**
1987      * @type {cc.EGLView}
1988      * @name cc.view
1989      * cc.view is the shared view object.
1990      */
1991     cc.view = cc.EGLView._getInstance();
1992     // register system events
1993     cc.inputManager.registerSystemEvent(cc._canvas);
1994 
1995     /**
1996      * @type {cc.Director}
1997      * @name cc.director
1998      */
1999     cc.director = cc.Director._getInstance();
2000     if (cc.director.setOpenGLView)
2001         cc.director.setOpenGLView(cc.view);
2002     /**
2003      * @type {cc.Size}
2004      * @name cc.winSize
2005      * cc.winSize is the alias object for the size of the current game window.
2006      */
2007     cc.winSize = cc.director.getWinSize();
2008 
2009     // Parsers
2010     cc.saxParser = new cc.SAXParser();
2011     /**
2012      * @type {cc.PlistParser}
2013      * @name cc.plistParser
2014      * A Plist Parser
2015      */
2016     cc.plistParser = new cc.PlistParser();
2017 };
2018 
2019 cc._checkWebGLRenderMode = function () {
2020     if (cc._renderType !== cc._RENDER_TYPE_WEBGL)
2021         throw "This feature supports WebGL render mode only.";
2022 };
2023 
2024 cc._isContextMenuEnable = false;
2025 /**
2026  * enable/disable contextMenu for Canvas
2027  * @param {Boolean} enabled
2028  */
2029 cc._setContextMenuEnable = function (enabled) {
2030     cc._isContextMenuEnable = enabled;
2031     cc._canvas.oncontextmenu = function () {
2032         if (!cc._isContextMenuEnable) return false;
2033     };
2034 };
2035 
2036 /**
2037  * An object to boot the game.
2038  * @class
2039  * @name cc.game
2040  */
2041 cc.game = /** @lends cc.game# */{
2042     DEBUG_MODE_NONE: 0,
2043     DEBUG_MODE_INFO: 1,
2044     DEBUG_MODE_WARN: 2,
2045     DEBUG_MODE_ERROR: 3,
2046     DEBUG_MODE_INFO_FOR_WEB_PAGE: 4,
2047     DEBUG_MODE_WARN_FOR_WEB_PAGE: 5,
2048     DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6,
2049 
2050     EVENT_HIDE: "game_on_hide",
2051     EVENT_SHOW: "game_on_show",
2052     _eventHide: null,
2053     _eventShow: null,
2054     _onBeforeStartArr: [],
2055 
2056     /**
2057      * Key of config
2058      * @constant
2059      * @type {Object}
2060      */
2061     CONFIG_KEY: {
2062         engineDir: "engineDir",
2063         dependencies: "dependencies",
2064         debugMode: "debugMode",
2065         showFPS: "showFPS",
2066         frameRate: "frameRate",
2067         id: "id",
2068         renderMode: "renderMode",
2069         jsList: "jsList",
2070         classReleaseMode: "classReleaseMode"
2071     },
2072 
2073     _prepareCalled: false,//whether the prepare function has been called
2074     _prepared: false,//whether the engine has prepared
2075     _paused: true,//whether the game is paused
2076 
2077     _intervalId: null,//interval target of main
2078     
2079     _lastTime: null,
2080     _frameTime: null,
2081 
2082     /**
2083      * Config of game
2084      * @type {Object}
2085      */
2086     config: null,
2087 
2088     /**
2089      * Callback when the scripts of engine have been load.
2090      * @type {Function}
2091      */
2092     onStart: null,
2093 
2094     /**
2095      * Callback when game exits.
2096      * @type {Function}
2097      */
2098     onStop: null,
2099 
2100     /**
2101      * Set frameRate of game.
2102      * @param frameRate
2103      */
2104     setFrameRate: function (frameRate) {
2105         var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY;
2106         config[CONFIG_KEY.frameRate] = frameRate;
2107         if (self._intervalId)
2108             window.cancelAnimationFrame(self._intervalId);
2109         self._paused = true;
2110         self._setAnimFrame();
2111         self._runMainLoop();
2112     },
2113     _setAnimFrame: function () {
2114         this._lastTime = new Date();
2115         this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate];
2116         if((cc.sys.os === cc.sys.OS_IOS && cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT) || cc.game.config[cc.game.CONFIG_KEY.frameRate] !== 60) {
2117             window.requestAnimFrame = this._stTime;
2118             window.cancelAnimationFrame = this._ctTime;
2119         }
2120         else {
2121             window.requestAnimFrame = window.requestAnimationFrame ||
2122             window.webkitRequestAnimationFrame ||
2123             window.mozRequestAnimationFrame ||
2124             window.oRequestAnimationFrame ||
2125             window.msRequestAnimationFrame ||
2126             this._stTime;
2127             window.cancelAnimationFrame = window.cancelAnimationFrame ||
2128             window.cancelRequestAnimationFrame ||
2129             window.msCancelRequestAnimationFrame ||
2130             window.mozCancelRequestAnimationFrame ||
2131             window.oCancelRequestAnimationFrame ||
2132             window.webkitCancelRequestAnimationFrame ||
2133             window.msCancelAnimationFrame ||
2134             window.mozCancelAnimationFrame ||
2135             window.webkitCancelAnimationFrame ||
2136             window.oCancelAnimationFrame ||
2137             this._ctTime;
2138         }
2139     },
2140     _stTime: function(callback){
2141         var currTime = new Date().getTime();
2142         var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime));
2143         var id = window.setTimeout(function() { callback(); },
2144             timeToCall);
2145         cc.game._lastTime = currTime + timeToCall;
2146         return id;
2147     },
2148     _ctTime: function(id){
2149         window.clearTimeout(id);
2150     },
2151     //Run game.
2152     _runMainLoop: function () {
2153         var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY,
2154             director = cc.director;
2155 
2156         director.setDisplayStats(config[CONFIG_KEY.showFPS]);
2157 
2158         callback = function () {
2159             if (!self._paused) {
2160                 director.mainLoop();
2161                 if(self._intervalId)
2162                     window.cancelAnimationFrame(self._intervalId);
2163                 self._intervalId = window.requestAnimFrame(callback);
2164             }
2165         };
2166 
2167         window.requestAnimFrame(callback);
2168         self._paused = false;
2169     },
2170 
2171     /**
2172      * Restart game.
2173      */
2174     restart: function () {
2175         cc.director.popToSceneStackLevel(0);
2176         // Clean up audio
2177         cc.audioEngine && cc.audioEngine.end();
2178 
2179         cc.game.onStart();
2180     },
2181 
2182     /**
2183      * Run game.
2184      */
2185     run: function (id) {
2186         var self = this;
2187         var _run = function () {
2188             if (id) {
2189                 self.config[self.CONFIG_KEY.id] = id;
2190             }
2191             if (!self._prepareCalled) {
2192                 self.prepare(function () {
2193                     self._prepared = true;
2194                 });
2195             }
2196             if (cc._supportRender) {
2197                 self._checkPrepare = setInterval(function () {
2198                     if (self._prepared) {
2199                         cc._setup(self.config[self.CONFIG_KEY.id]);
2200                         self._runMainLoop();
2201                         self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE);
2202                         self._eventHide.setUserData(self);
2203                         self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW);
2204                         self._eventShow.setUserData(self);
2205                         self.onStart();
2206                         clearInterval(self._checkPrepare);
2207                     }
2208                 }, 10);
2209             }
2210         };
2211         document.body ?
2212             _run() :
2213             cc._addEventListener(window, 'load', function () {
2214                 this.removeEventListener('load', arguments.callee, false);
2215                 _run();
2216             }, false);
2217     },
2218 
2219     _initConfig: function () {
2220         var self = this, CONFIG_KEY = self.CONFIG_KEY;
2221         var _init = function (cfg) {
2222             cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5";
2223             if(cfg[CONFIG_KEY.debugMode] == null)
2224                 cfg[CONFIG_KEY.debugMode] = 0;
2225             cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60;
2226             if(cfg[CONFIG_KEY.renderMode] == null)
2227                 cfg[CONFIG_KEY.renderMode] = 1;
2228             return cfg;
2229         };
2230         if (document["ccConfig"]) {
2231             self.config = _init(document["ccConfig"]);
2232         } else {
2233             try {
2234                 var cocos_script = document.getElementsByTagName('script');
2235                 for(var i=0;i<cocos_script.length;i++){
2236                     var _t = cocos_script[i].getAttribute('cocos');
2237                     if(_t === '' || _t){break;}
2238                 }
2239                 var _src, txt, _resPath;
2240                 if(i < cocos_script.length){
2241                     _src = cocos_script[i].src;
2242                     if(_src){
2243                         _resPath = /(.*)\//.exec(_src)[0];
2244                         cc.loader.resPath = _resPath;
2245                         _src = cc.path.join(_resPath, 'project.json');
2246                     }
2247                     txt = cc.loader._loadTxtSync(_src);
2248                 }
2249                 if(!txt){
2250                     txt = cc.loader._loadTxtSync("project.json");
2251                 }
2252                 var data = JSON.parse(txt);
2253                 self.config = _init(data || {});
2254             } catch (e) {
2255                 cc.log("Failed to read or parse project.json");
2256                 self.config = _init({});
2257             }
2258         }
2259         //init debug move to CCDebugger
2260         cc._initSys(self.config, CONFIG_KEY);
2261     },
2262 
2263     //cache for js and module that has added into jsList to be loaded.
2264     _jsAddedCache: {},
2265     _getJsListOfModule: function (moduleMap, moduleName, dir) {
2266         var jsAddedCache = this._jsAddedCache;
2267         if (jsAddedCache[moduleName]) return null;
2268         dir = dir || "";
2269         var jsList = [];
2270         var tempList = moduleMap[moduleName];
2271         if (!tempList) throw "can not find module [" + moduleName + "]";
2272         var ccPath = cc.path;
2273         for (var i = 0, li = tempList.length; i < li; i++) {
2274             var item = tempList[i];
2275             if (jsAddedCache[item]) continue;
2276             var extname = ccPath.extname(item);
2277             if (!extname) {
2278                 var arr = this._getJsListOfModule(moduleMap, item, dir);
2279                 if (arr) jsList = jsList.concat(arr);
2280             } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item));
2281             jsAddedCache[item] = 1;
2282         }
2283         return jsList;
2284     },
2285     /**
2286      * Prepare game.
2287      * @param cb
2288      */
2289     prepare: function (cb) {
2290         var self = this;
2291         var config = self.config, CONFIG_KEY = self.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader;
2292         if (!cc._supportRender) {
2293             throw "The renderer doesn't support the renderMode " + config[CONFIG_KEY.renderMode];
2294         }
2295         self._prepareCalled = true;
2296 
2297         var jsList = config[CONFIG_KEY.jsList] || [];
2298         if (cc.Class) {//is single file
2299             //load user's jsList only
2300             loader.loadJsWithImg("", jsList, function (err) {
2301                 if (err) throw err;
2302                 self._prepared = true;
2303                 if (cb) cb();
2304             });
2305         } else {
2306             //load cc's jsList first
2307             var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json");
2308             loader.loadJson(ccModulesPath, function (err, modulesJson) {
2309                 if (err) throw err;
2310                 var modules = config["modules"] || [];
2311                 var moduleMap = modulesJson["module"];
2312                 var newJsList = [];
2313                 if (cc._renderType === cc._RENDER_TYPE_WEBGL) modules.splice(0, 0, "shaders");
2314                 else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core");
2315                 for (var i = 0, li = modules.length; i < li; i++) {
2316                     var arr = self._getJsListOfModule(moduleMap, modules[i], engineDir);
2317                     if (arr) newJsList = newJsList.concat(arr);
2318                 }
2319                 newJsList = newJsList.concat(jsList);
2320                 cc.loader.loadJsWithImg(newJsList, function (err) {
2321                     if (err) throw err;
2322                     self._prepared = true;
2323                     if (cb) cb();
2324                 });
2325             });
2326         }
2327     }
2328 };
2329 cc.game._initConfig();
2330 //+++++++++++++++++++++++++something about CCGame end+++++++++++++++++++++++++++++
2331 
2332 Function.prototype.bind = Function.prototype.bind || function (oThis) {
2333     if (!cc.isFunction(this)) {
2334         // closest thing possible to the ECMAScript 5
2335         // internal IsCallable function
2336         throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
2337     }
2338 
2339     var aArgs = Array.prototype.slice.call(arguments, 1),
2340         fToBind = this,
2341         fNOP = function () {},
2342         fBound = function () {
2343             return fToBind.apply(this instanceof fNOP && oThis
2344                 ? this
2345                 : oThis,
2346                 aArgs.concat(Array.prototype.slice.call(arguments)));
2347         };
2348 
2349     fNOP.prototype = this.prototype;
2350     fBound.prototype = new fNOP();
2351 
2352     return fBound;
2353 };
2354