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