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