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