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 browserSupportWebGL = [sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_SAFARI];
1567     var osSupportWebGL = [sys.OS_IOS, sys.OS_WINDOWS, sys.OS_OSX, sys.OS_LINUX];
1568     var multipleAudioWhiteList = [
1569         sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP,
1570         sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE
1571     ];
1572 
1573     var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement;
1574     var ua = nav.userAgent.toLowerCase();
1575 
1576     /**
1577      * Indicate whether system is mobile system
1578      * @memberof cc.sys
1579      * @name isMobile
1580      * @type {Boolean}
1581      */
1582     sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1;
1583 
1584     /**
1585      * Indicate the running platform
1586      * @memberof cc.sys
1587      * @name platform
1588      * @type {Number}
1589      */
1590     sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER;
1591 
1592     var currLanguage = nav.language;
1593     currLanguage = currLanguage ? currLanguage : nav.browserLanguage;
1594     currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH;
1595 
1596     /**
1597      * Indicate the current language of the running system
1598      * @memberof cc.sys
1599      * @name language
1600      * @type {String}
1601      */
1602     sys.language = currLanguage;
1603 
1604     var browserType = sys.BROWSER_TYPE_UNKNOWN;
1605     var browserTypes = ua.match(/sogou|qzone|liebao|micromessenger|qqbrowser|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i)
1606         || ua.match(/chrome|safari/i);
1607     if (browserTypes && browserTypes.length > 0) {
1608         browserType = browserTypes[0];
1609         if (browserType === 'micromessenger') {
1610             browserType = sys.BROWSER_TYPE_WECHAT;
1611         } else if (browserType === "safari" && (ua.match(/android.*applewebkit/)))
1612             browserType = sys.BROWSER_TYPE_ANDROID;
1613         else if (browserType === "trident") browserType = sys.BROWSER_TYPE_IE;
1614         else if (browserType === "360 aphone") browserType = sys.BROWSER_TYPE_360;
1615     }else if(ua.indexOf("iphone") && ua.indexOf("mobile")){
1616         browserType = "safari";
1617     }
1618     /**
1619      * Indicate the running browser type
1620      * @memberof cc.sys
1621      * @name browserType
1622      * @type {String}
1623      */
1624     sys.browserType = browserType;
1625 
1626     // Get the os of system
1627     var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false );
1628     var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false;
1629     var osName = sys.OS_UNKNOWN;
1630     if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS;
1631     else if (iOS) osName = sys.OS_IOS;
1632     else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX;
1633     else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX;
1634     else if (isAndroid) osName = sys.OS_ANDROID;
1635     else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX;
1636 
1637     /**
1638      * Indicate the running os name
1639      * @memberof cc.sys
1640      * @name os
1641      * @type {String}
1642      */
1643     sys.os = osName;
1644 
1645     sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1;
1646 
1647 
1648     //++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++
1649     var userRenderMode = parseInt(config[CONFIG_KEY.renderMode]);
1650     var renderType = cc._RENDER_TYPE_WEBGL;
1651     var tempCanvas = cc.newElement("Canvas");
1652     cc._supportRender = true;
1653     var notSupportGL = true;
1654     if(iOS)
1655         notSupportGL = !window.WebGLRenderingContext || osSupportWebGL.indexOf(sys.os) === -1;
1656     else
1657         notSupportGL = !window.WebGLRenderingContext || browserSupportWebGL.indexOf(sys.browserType) === -1 || osSupportWebGL.indexOf(sys.os) === -1;
1658     if (userRenderMode === 1 || (userRenderMode === 0 && notSupportGL) || (location.origin === "file://"))
1659         renderType = cc._RENDER_TYPE_CANVAS;
1660 
1661     sys._canUseCanvasNewBlendModes = function(){
1662         var canvas = document.createElement('canvas');
1663         canvas.width = 1;
1664         canvas.height = 1;
1665         var context = canvas.getContext('2d');
1666         context.fillStyle = '#000';
1667         context.fillRect(0,0,1,1);
1668         context.globalCompositeOperation = 'multiply';
1669 
1670         var canvas2 = document.createElement('canvas');
1671         canvas2.width = 1;
1672         canvas2.height = 1;
1673         var context2 = canvas2.getContext('2d');
1674         context2.fillStyle = '#fff';
1675         context2.fillRect(0,0,1,1);
1676 
1677         context.drawImage(canvas2, 0, 0, 1, 1);
1678 
1679         return context.getImageData(0,0,1,1).data[0] === 0;
1680     };
1681 
1682     //Whether or not the Canvas BlendModes are supported.
1683     sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes();
1684 
1685     if (renderType === cc._RENDER_TYPE_WEBGL) {
1686         if (!win.WebGLRenderingContext
1687             || !cc.create3DContext(tempCanvas, {'stencil': true, 'preserveDrawingBuffer': true })) {
1688             if (userRenderMode === 0) renderType = cc._RENDER_TYPE_CANVAS;
1689             else cc._supportRender = false;
1690         }
1691     }
1692 
1693     if (renderType === cc._RENDER_TYPE_CANVAS) {
1694         try {
1695             tempCanvas.getContext("2d");
1696         } catch (e) {
1697             cc._supportRender = false;
1698         }
1699     }
1700     cc._renderType = renderType;
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      * Dump system informations
1785      * @memberof cc.sys
1786      * @name dump
1787      * @function
1788      */
1789     sys.dump = function () {
1790         var self = this;
1791         var str = "";
1792         str += "isMobile : " + self.isMobile + "\r\n";
1793         str += "language : " + self.language + "\r\n";
1794         str += "browserType : " + self.browserType + "\r\n";
1795         str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n";
1796         str += "os : " + self.os + "\r\n";
1797         str += "platform : " + self.platform + "\r\n";
1798         cc.log(str);
1799     }
1800 
1801     /**
1802      * Open a url in browser
1803      * @memberof cc.sys
1804      * @name openURL
1805      * @param {String} url
1806      */
1807     sys.openURL = function(url){
1808         window.open(url);
1809     }
1810 };
1811 
1812 //+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++
1813 
1814 //+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++
1815 
1816 /**
1817  * Device oriented vertically, home button on the bottom
1818  * @constant
1819  * @type {Number}
1820  */
1821 cc.ORIENTATION_PORTRAIT = 0;
1822 
1823 /**
1824  * Device oriented vertically, home button on the top
1825  * @constant
1826  * @type {Number}
1827  */
1828 cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1;
1829 
1830 /**
1831  * Device oriented horizontally, home button on the right
1832  * @constant
1833  * @type {Number}
1834  */
1835 cc.ORIENTATION_LANDSCAPE_LEFT = 2;
1836 
1837 /**
1838  * Device oriented horizontally, home button on the left
1839  * @constant
1840  * @type {Number}
1841  */
1842 cc.ORIENTATION_LANDSCAPE_RIGHT = 3;
1843 
1844 /**
1845  * drawing primitive of game engine
1846  * @type {cc.DrawingPrimitive}
1847  */
1848 cc._drawingUtil = null;
1849 
1850 /**
1851  * main Canvas 2D/3D Context of game engine
1852  * @type {CanvasRenderingContext2D|WebGLRenderingContext}
1853  */
1854 cc._renderContext = null;
1855 
1856 /**
1857  * main Canvas of game engine
1858  * @type {HTMLCanvasElement}
1859  */
1860 cc._canvas = null;
1861 
1862 /**
1863  * This Div element contain all game canvas
1864  * @type {HTMLDivElement}
1865  */
1866 cc._gameDiv = null;
1867 
1868 cc._rendererInitialized = false;
1869 /**
1870  * <p>
1871  *   setup game main canvas,renderContext,gameDiv and drawingUtil with argument  <br/>
1872  *   <br/>
1873  *   can receive follow type of arguemnt: <br/>
1874  *      - empty: create a canvas append to document's body, and setup other option    <br/>
1875  *      - string: search the element by document.getElementById(),    <br/>
1876  *          if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc._gameDiv.<br/>
1877  *          if this element is HTMLDivElement, set it's ParentNode to cc._gameDiv, and create a canvas as main canvas of engine.   <br/>
1878  * </p>
1879  * @function
1880  * @example
1881  * //setup with null
1882  * cc._setup();
1883  *
1884  * // setup with HTMLCanvasElement, gameCanvas is Canvas element
1885  * // declare like this: <canvas id="gameCanvas" width="800" height="450"></canvas>
1886  * cc._setup("gameCanvas");
1887  *
1888  * //setup with HTMLDivElement, gameDiv is Div element
1889  * // declare like this: <div id="Cocos2dGameContainer" width="800" height="450"></div>
1890  * cc._setup("Cocos2dGameContainer");
1891  */
1892 cc._setupCalled = false;
1893 cc._setup = function (el, width, height) {
1894     // Avoid setup to be called twice.
1895     if (cc._setupCalled) return;
1896     else cc._setupCalled = true;
1897     var win = window;
1898     var element = cc.$(el) || cc.$('#' + el);
1899     var localCanvas, localContainer, localConStyle;
1900 
1901     cc.game._setAnimFrame();
1902 
1903     if (element.tagName === "CANVAS") {
1904         width = width || element.width;
1905         height = height || element.height;
1906 
1907         //it is already a canvas, we wrap it around with a div
1908         localContainer = cc.container = cc.newElement("DIV");
1909         localCanvas = cc._canvas = element;
1910         localCanvas.parentNode.insertBefore(localContainer, localCanvas);
1911         localCanvas.appendTo(localContainer);
1912         localContainer.setAttribute('id', 'Cocos2dGameContainer');
1913     } else {//we must make a new canvas and place into this element
1914         if (element.tagName !== "DIV") {
1915             cc.log("Warning: target element is not a DIV or CANVAS");
1916         }
1917         width = width || element.clientWidth;
1918         height = height || element.clientHeight;
1919         localContainer = cc.container = element;
1920         localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS"));
1921         element.appendChild(localCanvas);
1922     }
1923 
1924     localCanvas.addClass("gameCanvas");
1925     localCanvas.setAttribute("width", width || 480);
1926     localCanvas.setAttribute("height", height || 320);
1927     localCanvas.setAttribute("tabindex", 99);
1928     localCanvas.style.outline = "none";
1929     localConStyle = localContainer.style;
1930     localConStyle.width = (width || 480) + "px";
1931     localConStyle.height = (height || 320) + "px";
1932     localConStyle.margin = "0 auto";
1933 
1934     localConStyle.position = 'relative';
1935     localConStyle.overflow = 'hidden';
1936     localContainer.top = '100%';
1937 
1938     if (cc._renderType === cc._RENDER_TYPE_WEBGL)
1939         cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, {
1940             'stencil': true,
1941             'preserveDrawingBuffer': true,
1942             'antialias': !cc.sys.isMobile,
1943             'alpha': false
1944         });
1945     if (cc._renderContext) {
1946         win.gl = cc._renderContext; // global variable declared in CCMacro.js
1947         cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext);
1948         cc._rendererInitialized = true;
1949         cc.textureCache._initializingRenderer();
1950         cc.shaderCache._init();
1951     } else {
1952         cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d"));
1953         cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null;
1954     }
1955 
1956     cc._gameDiv = localContainer;
1957     cc.log(cc.ENGINE_VERSION);
1958     cc._setContextMenuEnable(false);
1959 
1960     if (cc.sys.isMobile) {
1961         var fontStyle = cc.newElement("style");
1962         fontStyle.type = "text/css";
1963         document.body.appendChild(fontStyle);
1964 
1965         fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;"
1966             + "-webkit-tap-highlight-color:rgba(0,0,0,0);}";
1967     }
1968 
1969     // Init singletons
1970 
1971     /**
1972      * @type {cc.EGLView}
1973      * @name cc.view
1974      * cc.view is the shared view object.
1975      */
1976     cc.view = cc.EGLView._getInstance();
1977     // register system events
1978     cc.inputManager.registerSystemEvent(cc._canvas);
1979 
1980     /**
1981      * @type {cc.Director}
1982      * @name cc.director
1983      */
1984     cc.director = cc.Director._getInstance();
1985     if (cc.director.setOpenGLView)
1986         cc.director.setOpenGLView(cc.view);
1987     /**
1988      * @type {cc.Size}
1989      * @name cc.winSize
1990      * cc.winSize is the alias object for the size of the current game window.
1991      */
1992     cc.winSize = cc.director.getWinSize();
1993 
1994     // Parsers
1995     cc.saxParser = new cc.SAXParser();
1996     /**
1997      * @type {cc.PlistParser}
1998      * @name cc.plistParser
1999      * A Plist Parser
2000      */
2001     cc.plistParser = new cc.PlistParser();
2002 };
2003 
2004 cc._checkWebGLRenderMode = function () {
2005     if (cc._renderType !== cc._RENDER_TYPE_WEBGL)
2006         throw "This feature supports WebGL render mode only.";
2007 };
2008 
2009 cc._isContextMenuEnable = false;
2010 /**
2011  * enable/disable contextMenu for Canvas
2012  * @param {Boolean} enabled
2013  */
2014 cc._setContextMenuEnable = function (enabled) {
2015     cc._isContextMenuEnable = enabled;
2016     cc._canvas.oncontextmenu = function () {
2017         if (!cc._isContextMenuEnable) return false;
2018     };
2019 };
2020 
2021 /**
2022  * An object to boot the game.
2023  * @class
2024  * @name cc.game
2025  */
2026 cc.game = /** @lends cc.game# */{
2027     DEBUG_MODE_NONE: 0,
2028     DEBUG_MODE_INFO: 1,
2029     DEBUG_MODE_WARN: 2,
2030     DEBUG_MODE_ERROR: 3,
2031     DEBUG_MODE_INFO_FOR_WEB_PAGE: 4,
2032     DEBUG_MODE_WARN_FOR_WEB_PAGE: 5,
2033     DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6,
2034 
2035     EVENT_HIDE: "game_on_hide",
2036     EVENT_SHOW: "game_on_show",
2037     _eventHide: null,
2038     _eventShow: null,
2039     _onBeforeStartArr: [],
2040 
2041     /**
2042      * Key of config
2043      * @constant
2044      * @type {Object}
2045      */
2046     CONFIG_KEY: {
2047         engineDir: "engineDir",
2048         dependencies: "dependencies",
2049         debugMode: "debugMode",
2050         showFPS: "showFPS",
2051         frameRate: "frameRate",
2052         id: "id",
2053         renderMode: "renderMode",
2054         jsList: "jsList",
2055         classReleaseMode: "classReleaseMode"
2056     },
2057 
2058     _prepareCalled: false,//whether the prepare function has been called
2059     _prepared: false,//whether the engine has prepared
2060     _paused: true,//whether the game is paused
2061 
2062     _intervalId: null,//interval target of main
2063     
2064     _lastTime: null,
2065     _frameTime: null,
2066 
2067     /**
2068      * Config of game
2069      * @type {Object}
2070      */
2071     config: null,
2072 
2073     /**
2074      * Callback when the scripts of engine have been load.
2075      * @type {Function}
2076      */
2077     onStart: null,
2078 
2079     /**
2080      * Callback when game exits.
2081      * @type {Function}
2082      */
2083     onStop: null,
2084 
2085     /**
2086      * Set frameRate of game.
2087      * @param frameRate
2088      */
2089     setFrameRate: function (frameRate) {
2090         var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY;
2091         config[CONFIG_KEY.frameRate] = frameRate;
2092         if (self._intervalId)
2093             window.cancelAnimationFrame(self._intervalId);
2094         self._paused = true;
2095         self._setAnimFrame();
2096         self._runMainLoop();
2097     },
2098     _setAnimFrame: function () {
2099         this._lastTime = new Date();
2100         this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate];
2101         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) {
2102             window.requestAnimFrame = this._stTime;
2103             window.cancelAnimationFrame = this._ctTime;
2104         }
2105         else {
2106             window.requestAnimFrame = window.requestAnimationFrame ||
2107             window.webkitRequestAnimationFrame ||
2108             window.mozRequestAnimationFrame ||
2109             window.oRequestAnimationFrame ||
2110             window.msRequestAnimationFrame ||
2111             this._stTime;
2112             window.cancelAnimationFrame = window.cancelAnimationFrame ||
2113             window.cancelRequestAnimationFrame ||
2114             window.msCancelRequestAnimationFrame ||
2115             window.mozCancelRequestAnimationFrame ||
2116             window.oCancelRequestAnimationFrame ||
2117             window.webkitCancelRequestAnimationFrame ||
2118             window.msCancelAnimationFrame ||
2119             window.mozCancelAnimationFrame ||
2120             window.webkitCancelAnimationFrame ||
2121             window.oCancelAnimationFrame ||
2122             this._ctTime;
2123         }
2124     },
2125     _stTime: function(callback){
2126         var currTime = new Date().getTime();
2127         var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime));
2128         var id = window.setTimeout(function() { callback(); },
2129             timeToCall);
2130         cc.game._lastTime = currTime + timeToCall;
2131         return id;
2132     },
2133     _ctTime: function(id){
2134         window.clearTimeout(id);
2135     },
2136     //Run game.
2137     _runMainLoop: function () {
2138         var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY,
2139             director = cc.director;
2140 
2141         director.setDisplayStats(config[CONFIG_KEY.showFPS]);
2142 
2143         callback = function () {
2144             if (!self._paused) {
2145                 director.mainLoop();
2146                 if(self._intervalId)
2147                     window.cancelAnimationFrame(self._intervalId);
2148                 self._intervalId = window.requestAnimFrame(callback);
2149             }
2150         };
2151 
2152         window.requestAnimFrame(callback);
2153         self._paused = false;
2154     },
2155 
2156     /**
2157      * Restart game.
2158      */
2159     restart: function () {
2160         cc.director.popToSceneStackLevel(0);
2161         // Clean up audio
2162         cc.audioEngine && cc.audioEngine.end();
2163 
2164         cc.game.onStart();
2165     },
2166 
2167     /**
2168      * Run game.
2169      */
2170     run: function (id) {
2171         var self = this;
2172         var _run = function () {
2173             if (id) {
2174                 self.config[self.CONFIG_KEY.id] = id;
2175             }
2176             if (!self._prepareCalled) {
2177                 self.prepare(function () {
2178                     self._prepared = true;
2179                 });
2180             }
2181             if (cc._supportRender) {
2182                 self._checkPrepare = setInterval(function () {
2183                     if (self._prepared) {
2184                         cc._setup(self.config[self.CONFIG_KEY.id]);
2185                         self._runMainLoop();
2186                         self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE);
2187                         self._eventHide.setUserData(self);
2188                         self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW);
2189                         self._eventShow.setUserData(self);
2190                         self.onStart();
2191                         clearInterval(self._checkPrepare);
2192                     }
2193                 }, 10);
2194             }
2195         };
2196         document.body ?
2197             _run() :
2198             cc._addEventListener(window, 'load', function () {
2199                 this.removeEventListener('load', arguments.callee, false);
2200                 _run();
2201             }, false);
2202     },
2203 
2204     _initConfig: function () {
2205         var self = this, CONFIG_KEY = self.CONFIG_KEY;
2206         var _init = function (cfg) {
2207             cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5";
2208             if(cfg[CONFIG_KEY.debugMode] == null)
2209                 cfg[CONFIG_KEY.debugMode] = 0;
2210             cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60;
2211             if(cfg[CONFIG_KEY.renderMode] == null)
2212                 cfg[CONFIG_KEY.renderMode] = 1;
2213             return cfg;
2214         };
2215         if (document["ccConfig"]) {
2216             self.config = _init(document["ccConfig"]);
2217         } else {
2218             try {
2219                 var cocos_script = document.getElementsByTagName('script');
2220                 for(var i=0;i<cocos_script.length;i++){
2221                     var _t = cocos_script[i].getAttribute('cocos');
2222                     if(_t === '' || _t){break;}
2223                 }
2224                 var _src, txt, _resPath;
2225                 if(i < cocos_script.length){
2226                     _src = cocos_script[i].src;
2227                     if(_src){
2228                         _resPath = /(.*)\//.exec(_src)[0];
2229                         cc.loader.resPath = _resPath;
2230                         _src = cc.path.join(_resPath, 'project.json');
2231                     }
2232                     txt = cc.loader._loadTxtSync(_src);
2233                 }
2234                 if(!txt){
2235                     txt = cc.loader._loadTxtSync("project.json");
2236                 }
2237                 var data = JSON.parse(txt);
2238                 self.config = _init(data || {});
2239             } catch (e) {
2240                 cc.log("Failed to read or parse project.json");
2241                 self.config = _init({});
2242             }
2243         }
2244         //init debug move to CCDebugger
2245         cc._initSys(self.config, CONFIG_KEY);
2246     },
2247 
2248     //cache for js and module that has added into jsList to be loaded.
2249     _jsAddedCache: {},
2250     _getJsListOfModule: function (moduleMap, moduleName, dir) {
2251         var jsAddedCache = this._jsAddedCache;
2252         if (jsAddedCache[moduleName]) return null;
2253         dir = dir || "";
2254         var jsList = [];
2255         var tempList = moduleMap[moduleName];
2256         if (!tempList) throw "can not find module [" + moduleName + "]";
2257         var ccPath = cc.path;
2258         for (var i = 0, li = tempList.length; i < li; i++) {
2259             var item = tempList[i];
2260             if (jsAddedCache[item]) continue;
2261             var extname = ccPath.extname(item);
2262             if (!extname) {
2263                 var arr = this._getJsListOfModule(moduleMap, item, dir);
2264                 if (arr) jsList = jsList.concat(arr);
2265             } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item));
2266             jsAddedCache[item] = 1;
2267         }
2268         return jsList;
2269     },
2270     /**
2271      * Prepare game.
2272      * @param cb
2273      */
2274     prepare: function (cb) {
2275         var self = this;
2276         var config = self.config, CONFIG_KEY = self.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader;
2277         if (!cc._supportRender) {
2278             throw "The renderer doesn't support the renderMode " + config[CONFIG_KEY.renderMode];
2279         }
2280         self._prepareCalled = true;
2281 
2282         var jsList = config[CONFIG_KEY.jsList] || [];
2283         if (cc.Class) {//is single file
2284             //load user's jsList only
2285             loader.loadJsWithImg("", jsList, function (err) {
2286                 if (err) throw err;
2287                 self._prepared = true;
2288                 if (cb) cb();
2289             });
2290         } else {
2291             //load cc's jsList first
2292             var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json");
2293             loader.loadJson(ccModulesPath, function (err, modulesJson) {
2294                 if (err) throw err;
2295                 var modules = config["modules"] || [];
2296                 var moduleMap = modulesJson["module"];
2297                 var newJsList = [];
2298                 if (cc._renderType === cc._RENDER_TYPE_WEBGL) modules.splice(0, 0, "shaders");
2299                 else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core");
2300                 for (var i = 0, li = modules.length; i < li; i++) {
2301                     var arr = self._getJsListOfModule(moduleMap, modules[i], engineDir);
2302                     if (arr) newJsList = newJsList.concat(arr);
2303                 }
2304                 newJsList = newJsList.concat(jsList);
2305                 cc.loader.loadJsWithImg(newJsList, function (err) {
2306                     if (err) throw err;
2307                     self._prepared = true;
2308                     if (cb) cb();
2309                 });
2310             });
2311         }
2312     }
2313 };
2314 cc.game._initConfig();
2315 //+++++++++++++++++++++++++something about CCGame end+++++++++++++++++++++++++++++
2316 
2317 Function.prototype.bind = Function.prototype.bind || function (oThis) {
2318     if (!cc.isFunction(this)) {
2319         // closest thing possible to the ECMAScript 5
2320         // internal IsCallable function
2321         throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
2322     }
2323 
2324     var aArgs = Array.prototype.slice.call(arguments, 1),
2325         fToBind = this,
2326         fNOP = function () {},
2327         fBound = function () {
2328             return fToBind.apply(this instanceof fNOP && oThis
2329                 ? this
2330                 : oThis,
2331                 aArgs.concat(Array.prototype.slice.call(arguments)));
2332         };
2333 
2334     fNOP.prototype = this.prototype;
2335     fBound.prototype = new fNOP();
2336 
2337     return fBound;
2338 };
2339