码迷,mamicode.com
首页 > Windows程序 > 详细

用Windjs画圆

时间:2015-01-12 20:41:38      阅读:397      评论:0      收藏:0      [点我收藏+]

标签:

  无意中接触了jscex,也就是Wind.js的前身,深深被它和它的作者老赵吸引。该轻量级js库是为了实现异步编程所设计的,可能因为eval的种种不安全因素或者应用不是很广的原因至今也没很大程度上的推广,从github上来看代码也已经两年多没更新了,但是还是有必要写几个小的demo的,毕竟下份需要阅读的代码中有用到该类库。

  先写个canvas上画圆的demo。

  等等,画圆?开玩笑,arc简单搞定!那么,要是不用h5的api自己来写这个函数呢?动手画了下感觉还是蛮easy的:

技术分享
 1 <!DOCTYPE html>
 2 <html>
 3   <head>
 4     <link rel="stylesheet" href="reset.css">
 5     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 6     <title> </title>
 7     <script src="jquery.js"></script>
 8     <script src="wind-all-0.7.3.js"></script>
 9     <script>
10       window.onload = function() {
11         var canvas = document.getElementById("canvas");
12         var ctx = canvas.getContext("2d");
13         var x = 250;
14         var y = 250;
15         var r = 100;
16         var frontX = x - r;
17         var frontY = y;
18 
19         for(var i = x - r; i <= x + r; i++) {
20           var tempY = Math.sqrt(r * r - (x - i) * (x - i));
21           ctx.beginPath();
22           ctx.moveTo(frontX, frontY);
23           ctx.lineTo(i, y+  tempY);
24           ctx.stroke();
25           frontX = i;
26           frontY = y + tempY;
27         }
28         
29         for(var i = x + r; i >= x - r; i--) {
30           var tempY = Math.sqrt(r * r - (x - i) * (x - i));
31           ctx.beginPath();
32           ctx.moveTo(frontX, frontY);
33           ctx.lineTo(i, y - tempY);
34           ctx.stroke();
35           frontX = i;
36           frontY = y - tempY;
37         }
38       };
39     </script>
40   </head>
41   <body>
42     <canvas id=‘canvas‘ width=500 height=500 style=‘border:1px solid red‘>
43     </canvas>
44   </body>
45 </html>
View Code

  这里为了写的规范点,用了beginPath。不用beginPath有时会出现些莫名其妙的错误,值得注意。

  那么,进步一想,能不能在画布上显示绘制过程呢?

  what?开玩笑吧,我们都知道js这样的解释型语言,解释完了也就画完了,咋可能显示绘制过程?

  等等,let me have a try,看看能不能用setTimeout?将stroke函数设置个定时器,约定1s后执行,那么能不能出现1s绘制一帧的效果呢?

  很遗憾,事实上是没有的,实际的效果是1s后全部绘图一瞬间完成,因为for循环就在一瞬间,然后所有的setTimeout同时累计起来了,what a pity!

  技术分享

  这时我们祭出大杀器Windjs!改写后的代码如下:

技术分享
 1 <!DOCTYPE html>
 2 <html>
 3   <head>
 4     <link rel="stylesheet" href="reset.css">
 5     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 6     <title> </title>
 7     <script src="jquery.js"></script>
 8     <script src="wind-all-0.7.3.js"></script>
 9     <script>
10       window.onload = function() {
11         var canvas = document.getElementById("canvas");
12         var ctx = canvas.getContext("2d");
13         var x = 250;
14         var y = 250;
15         var r = 100;
16         var frontX = x - r;
17         var frontY = y;
18 
19         var drawAsync = eval(Wind.compile(async, function() {
20           for(var i = x - r; i <= x + r; i++) {
21             var tempY = Math.sqrt(r * r - (x - i) * (x - i));
22             ctx.beginPath();
23             ctx.moveTo(frontX, frontY);
24             ctx.lineTo(i, y+  tempY);
25             $await(Wind.Async.sleep(10));
26             ctx.stroke();
27             frontX = i;
28             frontY = y + tempY;
29           }
30         
31           for(var i = x + r; i >= x - r; i--) {
32             var tempY = Math.sqrt(r * r - (x - i) * (x - i));
33             ctx.beginPath();
34             ctx.moveTo(frontX, frontY);
35             ctx.lineTo(i, y - tempY);
36             $await(Wind.Async.sleep(10));
37             ctx.stroke();
38             frontX = i;
39             frontY = y - tempY;
40           }
41         }));
42 
43         drawAsync().start();
44       };
45     </script>
46   </head>
47   <body>
48     <canvas id=‘canvas‘ width=500 height=500 style=‘border:1px solid red‘>
49     </canvas>
50   </body>
51 </html>
View Code

  what a pass!来自Windjs的助攻成功地完成了不可能完成的任务!

  ps:Wind.js备份

技术分享
   1 /***********************************************************************
   2   wind-core-0.7.0.js
   3  ***********************************************************************/
   4 
   5 (function () {
   6     "use strict";
   7     
   8     var Wind;
   9     
  10     var _ = (function () {
  11     
  12         var isArray = function (obj) {
  13             return Object.prototype.toString.call(obj) === ‘[object Array]‘;
  14         }
  15     
  16         var each = function (obj, action) {
  17             if (isArray(obj)) {
  18                 for (var i = 0, len = obj.length; i < len; i++) {
  19                     var value = action.length === 1 ? action(obj[i]) : action(i, obj[i]);
  20                     if (value !== undefined)
  21                         return value;
  22                 }
  23             } else {
  24                 for (var key in obj) {
  25                     if (obj.hasOwnProperty(key)) {
  26                         var value = action.length === 1 ? action(obj[key]) : action(key, obj[key]);
  27                         if (value !== undefined)
  28                             return value;
  29                     }
  30                 }
  31             }
  32         }
  33         
  34         var isEmpty = function (obj) {
  35             if (isArray(obj)) {
  36                 return obj.length === 0;
  37             }
  38             
  39             return !(_.each(obj, function (v) { return true; }));
  40         }
  41         
  42         var map = function (obj, mapper, valueMapper) {
  43             if (isArray(obj)) {
  44                 var array = new Array(obj.length);
  45                 for (var i = 0, len = obj.length; i < len; i++) {
  46                     array[i] = mapper(obj[i]);
  47                 }
  48                 return array;
  49             } else {
  50                 var keyMapper = valueMapper ? mapper : null;
  51                 valueMapper = valueMapper || mapper;
  52                 
  53                 var newObj = {};
  54                 for (var key in obj) {
  55                     if (obj.hasOwnProperty(key)) {
  56                         var value = obj[key];
  57                         var newKey = keyMapper ? keyMapper(key) : key;
  58                         var newValue = valueMapper ? valueMapper(value) : value;
  59                         newObj[newKey] = newValue;
  60                     }
  61                 }
  62 
  63                 return newObj;
  64             }
  65         }
  66 
  67         var clone = function (obj) {
  68             return map(obj);
  69         }
  70         
  71         var v2n = function (version) {
  72             var value = 0;
  73             
  74             var parts = version.split(".");
  75             for (var i = 0; i < 3; i++) {
  76                 value *= 100;
  77                 if (i < parts.length) {
  78                     value += parseInt(parts[i], 10);
  79                 }
  80             }
  81             
  82             return value;
  83         }
  84         
  85         var testVersion = function (expected, version) {
  86             var expectedMinVersion = expected.substring(1); // remove leading "~"
  87             
  88             var expectedMaxParts = expectedMinVersion.split(".");
  89             expectedMaxParts[expectedMaxParts.length - 1] = "0";
  90             expectedMaxParts[expectedMaxParts.length - 2] = (parseInt(expectedMaxParts[expectedMaxParts.length - 2], 10) + 1).toString();
  91             var expectedMaxVersion = expectedMaxParts.join(".");
  92             
  93             var versionNumber = v2n(version);
  94             return v2n(expectedMinVersion) <= versionNumber && versionNumber < v2n(expectedMaxVersion);
  95         }
  96         
  97         var format = function (f, args) {
  98             // support _.format(f, a0, a1, ...);
  99             if (!isArray(args)) {
 100                 var newArgs = new Array(arguments.length - 1);
 101                 for (var i = 1; i < arguments.length; i++) {
 102                     newArgs[i - 1] = arguments[i];
 103                 }
 104                 
 105                 return format(f, newArgs);
 106             }
 107             
 108             return f.replace(/\{{1,2}\d+\}{1,2}/g, function (ph) {
 109                 if (ph.indexOf("{{") == 0 && ph.indexOf("}}") == ph.length - 2) {
 110                     return ph.substring(1, ph.length - 1);
 111                 }
 112                 
 113                 var left = 0;
 114                 while (ph[left] == "{") left++;
 115                 
 116                 var right = ph.length - 1;
 117                 while (ph[right] == "}") right--;
 118                 
 119                 var index = parseInt(ph.substring(left, right + 1), 10);
 120                 return ph.replace("{" + index + "}", args[index]);
 121             });
 122         }
 123         
 124         var once = function (fn) {
 125             var called = false;
 126             return function () {
 127                 if (called) return;
 128                 fn.apply(this, arguments);
 129                 called = true;
 130             }
 131         };
 132         
 133         return {
 134             isArray: isArray,
 135             each: each,
 136             isEmpty: isEmpty,
 137             map: map,
 138             clone: clone,
 139             v2n: v2n,
 140             testVersion: testVersion,
 141             format: format,
 142             once: once
 143         };
 144     })();
 145 
 146     var Level = {
 147         ALL: 0,
 148         TRACE: 1,
 149         DEBUG: 2,
 150         INFO: 3,
 151         WARN: 4,
 152         ERROR: 5,
 153         OFF: 100
 154     };
 155 
 156     var Logger = function () {
 157         this.level = Level.DEBUG;
 158     };
 159     Logger.prototype = {
 160         log: function (level, msg) {
 161             if (this.level <= level) {
 162                 try { console.log(msg); } catch (ex) { }
 163             }
 164         },
 165 
 166         trace: function (msg) {
 167             this.log(Level.TRACE, msg);
 168         },
 169 
 170         debug: function (msg) {
 171             this.log(Level.DEBUG, msg);
 172         },
 173 
 174         info: function (msg) {
 175             this.log(Level.INFO, msg);
 176         },
 177 
 178         warn: function (msg) {
 179             this.log(Level.WARN, msg);
 180         },
 181 
 182         error: function (msg) {
 183             this.log(Level.ERROR, msg);
 184         }
 185     };
 186 
 187     var exportBasicOptions = function (exports, options) {
 188         exports.name = options.name;
 189         exports.version = options.version;
 190         
 191         if (options.autoloads) {
 192             exports.autoloads = options.autoloads;
 193         }
 194         
 195         if (options.dependencies) {
 196             exports.dependencies = options.dependencies;
 197         }
 198     }
 199     
 200     var initModule = function (options) {
 201         var existingModule = Wind.modules[options.name];
 202         if (existingModule && existingModule.version != options.version) {
 203             Wind.logger.warn(_.format(
 204                 ‘The module "{0}" with version "{1}" has already been initialized, skip version "{2}".‘,
 205                 options.name,
 206                 existingModule.version,
 207                 options.version));
 208         }
 209 
 210         checkDependencies(options);
 211         options.init();
 212         
 213         var module = {};
 214         exportBasicOptions(module, options);
 215         Wind.modules[options.name] = module;
 216     }
 217     
 218     var checkDependencies = function (options) {
 219         _.each(options.dependencies || [], function (name, expectedVersion) {
 220             var module = Wind.modules[name];
 221             if (!module) {
 222                 throw new Error(_.format(
 223                     ‘Missing required module: "{0}" (expected version: "{1}").‘,
 224                     name,
 225                     expectedVersion));
 226             }
 227 
 228             if (!_.testVersion(expectedVersion, module.version)) {
 229                 throw new Error(_.format(
 230                     ‘Version of module "{0}" mismatched, expected: "{1}", actual: "{2}".‘,
 231                     name,
 232                     expectedVersion,
 233                     module.version));
 234             }
 235         });
 236     }
 237 
 238     // CommonJS
 239     var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);
 240     // CommonJS AMD
 241     var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);
 242     
 243     var defineModule = function (options) {
 244         var autoloads = options.autoloads || [];
 245 
 246         if (isCommonJS) {
 247             var require = options.require;
 248             _.each(autoloads, function (name) {
 249                 try {
 250                     require("./wind-" + name);
 251                 } catch (ex) {
 252                     require("wind-" + name);
 253                 }
 254             });
 255             
 256             initModule(options);
 257         } else if (isAmd) {
 258             var dependencies = _.map(autoloads, function (name) { return "wind-" + name; });
 259             define("wind-" + options.name, dependencies, function () {
 260                 if (options.onerror) {
 261                     try {
 262                         initModule(options);
 263                     } catch (ex) {
 264                         options.onerror(ex);
 265                     }
 266                 } else {
 267                     initModule(options);
 268                 }
 269             });
 270         } else {
 271             initModule(options);
 272         }
 273     }
 274 
 275     var init = function () {
 276         Wind.logger = new Logger();
 277         Wind.Logging = {
 278             Logger: Logger,
 279             Level: Level
 280         };
 281 
 282         Wind._ = _;
 283         Wind.modules = { core: { name: "core", version: "0.7.0" } };
 284         Wind.binders = { };
 285         Wind.builders = { };
 286         Wind.define = defineModule;
 287     };
 288     
 289     if (isCommonJS) {
 290         Wind = module.exports;
 291         init();
 292     } else if (isAmd) {
 293         define("wind-core", function () {
 294             Wind = { };
 295             init();
 296             return Wind;
 297         });
 298     } else {
 299         // Get the global object.
 300         var Fn = Function, global = Fn(‘return this‘)();
 301     
 302         if (global.Wind) {
 303             throw new Error("There‘s already a Wind root here, please load the component only once.");
 304         }
 305         
 306         Wind = global.Wind = { };
 307         init();
 308     }
 309 })();
 310 
 311 /***********************************************************************
 312   wind-compiler-0.7.2.js
 313  ***********************************************************************/
 314 
 315 (function () {
 316     "use strict";
 317 
 318     var parse = (function () {
 319 
 320         /***********************************************************************
 321 
 322           A JavaScript tokenizer / parser / beautifier / compressor.
 323 
 324           This version is suitable for Node.js.  With minimal changes (the
 325           exports stuff) it should work on any JS platform.
 326 
 327           This file contains the tokenizer/parser.  It is a port to JavaScript
 328           of parse-js [1], a JavaScript parser library written in Common Lisp
 329           by Marijn Haverbeke.  Thank you Marijn!
 330 
 331           [1] http://marijn.haverbeke.nl/parse-js/
 332 
 333           Exported functions:
 334 
 335             - tokenizer(code) -- returns a function.  Call the returned
 336               function to fetch the next token.
 337 
 338             - parse(code) -- returns an AST of the given JavaScript code.
 339 
 340           -------------------------------- (C) ---------------------------------
 341 
 342                                    Author: Mihai Bazon
 343                                  <mihai.bazon@gmail.com>
 344                                http://mihai.bazon.net/blog
 345 
 346           Distributed under the BSD license:
 347 
 348             Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
 349             Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
 350 
 351             Redistribution and use in source and binary forms, with or without
 352             modification, are permitted provided that the following conditions
 353             are met:
 354 
 355                 * Redistributions of source code must retain the above
 356                   copyright notice, this list of conditions and the following
 357                   disclaimer.
 358 
 359                 * Redistributions in binary form must reproduce the above
 360                   copyright notice, this list of conditions and the following
 361                   disclaimer in the documentation and/or other materials
 362                   provided with the distribution.
 363 
 364             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
 365             EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 366             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 367             PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
 368             LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 369             OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 370             PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 371             PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 372             THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 373             TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 374             THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 375             SUCH DAMAGE.
 376 
 377          ***********************************************************************/
 378 
 379         /* -----[ Tokenizer (constants) ]----- */
 380 
 381         var KEYWORDS = array_to_hash([
 382                 "break",
 383                 "case",
 384                 "catch",
 385                 "const",
 386                 "continue",
 387                 "default",
 388                 "delete",
 389                 "do",
 390                 "else",
 391                 "finally",
 392                 "for",
 393                 "function",
 394                 "if",
 395                 "in",
 396                 "instanceof",
 397                 "new",
 398                 "return",
 399                 "switch",
 400                 "throw",
 401                 "try",
 402                 "typeof",
 403                 "var",
 404                 "void",
 405                 "while",
 406                 "with"
 407         ]);
 408 
 409         var RESERVED_WORDS = array_to_hash([
 410                 "abstract",
 411                 "boolean",
 412                 "byte",
 413                 "char",
 414                 "class",
 415                 "debugger",
 416                 "double",
 417                 "enum",
 418                 "export",
 419                 "extends",
 420                 "final",
 421                 "float",
 422                 "goto",
 423                 "implements",
 424                 "import",
 425                 "int",
 426                 "interface",
 427                 "long",
 428                 "native",
 429                 "package",
 430                 "private",
 431                 "protected",
 432                 "public",
 433                 "short",
 434                 "static",
 435                 "super",
 436                 "synchronized",
 437                 "throws",
 438                 "transient",
 439                 "volatile"
 440         ]);
 441 
 442         var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
 443                 "return",
 444                 "new",
 445                 "delete",
 446                 "throw",
 447                 "else",
 448                 "case"
 449         ]);
 450 
 451         var KEYWORDS_ATOM = array_to_hash([
 452                 "false",
 453                 "null",
 454                 "true",
 455                 "undefined"
 456         ]);
 457 
 458         var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
 459 
 460         var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
 461         var RE_OCT_NUMBER = /^0[0-7]+$/;
 462         var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
 463 
 464         var OPERATORS = array_to_hash([
 465                 "in",
 466                 "instanceof",
 467                 "typeof",
 468                 "new",
 469                 "void",
 470                 "delete",
 471                 "++",
 472                 "--",
 473                 "+",
 474                 "-",
 475                 "!",
 476                 "~",
 477                 "&",
 478                 "|",
 479                 "^",
 480                 "*",
 481                 "/",
 482                 "%",
 483                 ">>",
 484                 "<<",
 485                 ">>>",
 486                 "<",
 487                 ">",
 488                 "<=",
 489                 ">=",
 490                 "==",
 491                 "===",
 492                 "!=",
 493                 "!==",
 494                 "?",
 495                 "=",
 496                 "+=",
 497                 "-=",
 498                 "/=",
 499                 "*=",
 500                 "%=",
 501                 ">>=",
 502                 "<<=",
 503                 ">>>=",
 504                 "|=",
 505                 "^=",
 506                 "&=",
 507                 "&&",
 508                 "||"
 509         ]);
 510 
 511         var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t\u200b"));
 512 
 513         var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
 514 
 515         var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
 516 
 517         var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
 518 
 519         /* -----[ Tokenizer ]----- */
 520 
 521         // regexps adapted from http://xregexp.com/plugins/#unicode
 522         var UNICODE = {
 523                 letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
 524                 non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
 525                 space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
 526                 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
 527         };
 528 
 529         function is_letter(ch) {
 530                 return UNICODE.letter.test(ch);
 531         };
 532 
 533         function is_digit(ch) {
 534                 ch = ch.charCodeAt(0);
 535                 return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
 536         };
 537 
 538         function is_alphanumeric_char(ch) {
 539                 return is_digit(ch) || is_letter(ch);
 540         };
 541 
 542         function is_unicode_combining_mark(ch) {
 543                 return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
 544         };
 545 
 546         function is_unicode_connector_punctuation(ch) {
 547                 return UNICODE.connector_punctuation.test(ch);
 548         };
 549 
 550         function is_identifier_start(ch) {
 551                 return ch == "$" || ch == "_" || is_letter(ch);
 552         };
 553 
 554         function is_identifier_char(ch) {
 555                 return is_identifier_start(ch)
 556                         || is_unicode_combining_mark(ch)
 557                         || is_digit(ch)
 558                         || is_unicode_connector_punctuation(ch)
 559                         || ch == "\u200c" // zero-width non-joiner <ZWNJ>
 560                         || ch == "\u200d" // zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
 561                 ;
 562         };
 563 
 564         function parse_js_number(num) {
 565                 if (RE_HEX_NUMBER.test(num)) {
 566                         return parseInt(num.substr(2), 16);
 567                 } else if (RE_OCT_NUMBER.test(num)) {
 568                         return parseInt(num.substr(1), 8);
 569                 } else if (RE_DEC_NUMBER.test(num)) {
 570                         return parseFloat(num);
 571                 }
 572         };
 573 
 574         function JS_Parse_Error(message, line, col, pos) {
 575                 this.message = message;
 576                 this.line = line;
 577                 this.col = col;
 578                 this.pos = pos;
 579                 try {
 580                         ({})();
 581                 } catch(ex) {
 582                         this.stack = ex.stack;
 583                 };
 584         };
 585 
 586         JS_Parse_Error.prototype.toString = function() {
 587                 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
 588         };
 589 
 590         function js_error(message, line, col, pos) {
 591                 throw new JS_Parse_Error(message, line, col, pos);
 592         };
 593 
 594         function is_token(token, type, val) {
 595                 return token.type == type && (val == null || token.value == val);
 596         };
 597 
 598         var EX_EOF = {};
 599 
 600         function tokenizer($TEXT) {
 601 
 602                 var S = {
 603                         text            : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ‘‘),
 604                         pos             : 0,
 605                         tokpos          : 0,
 606                         line            : 0,
 607                         tokline         : 0,
 608                         col             : 0,
 609                         tokcol          : 0,
 610                         newline_before  : false,
 611                         regex_allowed   : false,
 612                         comments_before : []
 613                 };
 614 
 615                 function peek() { return S.text.charAt(S.pos); };
 616 
 617                 function next(signal_eof) {
 618                         var ch = S.text.charAt(S.pos++);
 619                         if (signal_eof && !ch)
 620                                 throw EX_EOF;
 621                         if (ch == "\n") {
 622                                 S.newline_before = true;
 623                                 ++S.line;
 624                                 S.col = 0;
 625                         } else {
 626                                 ++S.col;
 627                         }
 628                         return ch;
 629                 };
 630 
 631                 function eof() {
 632                         return !S.peek();
 633                 };
 634 
 635                 function find(what, signal_eof) {
 636                         var pos = S.text.indexOf(what, S.pos);
 637                         if (signal_eof && pos == -1) throw EX_EOF;
 638                         return pos;
 639                 };
 640 
 641                 function start_token() {
 642                         S.tokline = S.line;
 643                         S.tokcol = S.col;
 644                         S.tokpos = S.pos;
 645                 };
 646 
 647                 function token(type, value, is_comment) {
 648                         S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
 649                                            (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
 650                                            (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
 651                         var ret = {
 652                                 type  : type,
 653                                 value : value,
 654                                 line  : S.tokline,
 655                                 col   : S.tokcol,
 656                                 pos   : S.tokpos,
 657                                 nlb   : S.newline_before
 658                         };
 659                         if (!is_comment) {
 660                                 ret.comments_before = S.comments_before;
 661                                 S.comments_before = [];
 662                         }
 663                         S.newline_before = false;
 664                         return ret;
 665                 };
 666 
 667                 function skip_whitespace() {
 668                         while (HOP(WHITESPACE_CHARS, peek()))
 669                                 next();
 670                 };
 671 
 672                 function read_while(pred) {
 673                         var ret = "", ch = peek(), i = 0;
 674                         while (ch && pred(ch, i++)) {
 675                                 ret += next();
 676                                 ch = peek();
 677                         }
 678                         return ret;
 679                 };
 680 
 681                 function parse_error(err) {
 682                         js_error(err, S.tokline, S.tokcol, S.tokpos);
 683                 };
 684 
 685                 function read_num(prefix) {
 686                         var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
 687                         var num = read_while(function(ch, i){
 688                                 if (ch == "x" || ch == "X") {
 689                                         if (has_x) return false;
 690                                         return has_x = true;
 691                                 }
 692                                 if (!has_x && (ch == "E" || ch == "e")) {
 693                                         if (has_e) return false;
 694                                         return has_e = after_e = true;
 695                                 }
 696                                 if (ch == "-") {
 697                                         if (after_e || (i == 0 && !prefix)) return true;
 698                                         return false;
 699                                 }
 700                                 if (ch == "+") return after_e;
 701                                 after_e = false;
 702                                 if (ch == ".") {
 703                                         if (!has_dot && !has_x)
 704                                                 return has_dot = true;
 705                                         return false;
 706                                 }
 707                                 return is_alphanumeric_char(ch);
 708                         });
 709                         if (prefix)
 710                                 num = prefix + num;
 711                         var valid = parse_js_number(num);
 712                         if (!isNaN(valid)) {
 713                                 return token("num", valid);
 714                         } else {
 715                                 parse_error("Invalid syntax: " + num);
 716                         }
 717                 };
 718 
 719                 function read_escaped_char() {
 720                         var ch = next(true);
 721                         switch (ch) {
 722                             case "n" : return "\n";
 723                             case "r" : return "\r";
 724                             case "t" : return "\t";
 725                             case "b" : return "\b";
 726                             case "v" : return "\v";
 727                             case "f" : return "\f";
 728                             case "0" : return "\0";
 729                             case "x" : return String.fromCharCode(hex_bytes(2));
 730                             case "u" : return String.fromCharCode(hex_bytes(4));
 731                             default  : return ch;
 732                         }
 733                 };
 734 
 735                 function hex_bytes(n) {
 736                         var num = 0;
 737                         for (; n > 0; --n) {
 738                                 var digit = parseInt(next(true), 16);
 739                                 if (isNaN(digit))
 740                                         parse_error("Invalid hex-character pattern in string");
 741                                 num = (num << 4) | digit;
 742                         }
 743                         return num;
 744                 };
 745 
 746                 function read_string() {
 747                         return with_eof_error("Unterminated string constant", function(){
 748                                 var quote = next(), ret = "";
 749                                 for (;;) {
 750                                         var ch = next(true);
 751                                         if (ch == "\\") ch = read_escaped_char();
 752                                         else if (ch == quote) break;
 753                                         ret += ch;
 754                                 }
 755                                 return token("string", ret);
 756                         });
 757                 };
 758 
 759                 function read_line_comment() {
 760                         next();
 761                         var i = find("\n"), ret;
 762                         if (i == -1) {
 763                                 ret = S.text.substr(S.pos);
 764                                 S.pos = S.text.length;
 765                         } else {
 766                                 ret = S.text.substring(S.pos, i);
 767                                 S.pos = i;
 768                         }
 769                         return token("comment1", ret, true);
 770                 };
 771 
 772                 function read_multiline_comment() {
 773                         next();
 774                         return with_eof_error("Unterminated multiline comment", function(){
 775                                 var i = find("*/", true),
 776                                     text = S.text.substring(S.pos, i),
 777                                     tok = token("comment2", text, true);
 778                                 S.pos = i + 2;
 779                                 S.line += text.split("\n").length - 1;
 780                                 S.newline_before = text.indexOf("\n") >= 0;
 781 
 782                                 // https://github.com/mishoo/UglifyJS/issues/#issue/100
 783                                 if (/^@cc_on/i.test(text)) {
 784                                         warn("WARNING: at line " + S.line);
 785                                         warn("*** Found \"conditional comment\": " + text);
 786                                         warn("*** UglifyJS DISCARDS ALL COMMENTS.  This means your code might no longer work properly in Internet Explorer.");
 787                                 }
 788 
 789                                 return tok;
 790                         });
 791                 };
 792 
 793                 function read_name() {
 794                         var backslash = false, name = "", ch;
 795                         while ((ch = peek()) != null) {
 796                                 if (!backslash) {
 797                                         if (ch == "\\") backslash = true, next();
 798                                         else if (is_identifier_char(ch)) name += next();
 799                                         else break;
 800                                 }
 801                                 else {
 802                                         if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
 803                                         ch = read_escaped_char();
 804                                         if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
 805                                         name += ch;
 806                                         backslash = false;
 807                                 }
 808                         }
 809                         return name;
 810                 };
 811 
 812                 function read_regexp() {
 813                         return with_eof_error("Unterminated regular expression", function(){
 814                                 var prev_backslash = false, regexp = "", ch, in_class = false;
 815                                 while ((ch = next(true))) if (prev_backslash) {
 816                                         regexp += "\\" + ch;
 817                                         prev_backslash = false;
 818                                 } else if (ch == "[") {
 819                                         in_class = true;
 820                                         regexp += ch;
 821                                 } else if (ch == "]" && in_class) {
 822                                         in_class = false;
 823                                         regexp += ch;
 824                                 } else if (ch == "/" && !in_class) {
 825                                         break;
 826                                 } else if (ch == "\\") {
 827                                         prev_backslash = true;
 828                                 } else {
 829                                         regexp += ch;
 830                                 }
 831                                 var mods = read_name();
 832                                 return token("regexp", [ regexp, mods ]);
 833                         });
 834                 };
 835 
 836                 function read_operator(prefix) {
 837                         function grow(op) {
 838                                 if (!peek()) return op;
 839                                 var bigger = op + peek();
 840                                 if (HOP(OPERATORS, bigger)) {
 841                                         next();
 842                                         return grow(bigger);
 843                                 } else {
 844                                         return op;
 845                                 }
 846                         };
 847                         return token("operator", grow(prefix || next()));
 848                 };
 849 
 850                 function handle_slash() {
 851                         next();
 852                         var regex_allowed = S.regex_allowed;
 853                         switch (peek()) {
 854                             case "/":
 855                                 S.comments_before.push(read_line_comment());
 856                                 S.regex_allowed = regex_allowed;
 857                                 return next_token();
 858                             case "*":
 859                                 S.comments_before.push(read_multiline_comment());
 860                                 S.regex_allowed = regex_allowed;
 861                                 return next_token();
 862                         }
 863                         return S.regex_allowed ? read_regexp() : read_operator("/");
 864                 };
 865 
 866                 function handle_dot() {
 867                         next();
 868                         return is_digit(peek())
 869                                 ? read_num(".")
 870                                 : token("punc", ".");
 871                 };
 872 
 873                 function read_word() {
 874                         var word = read_name();
 875                         return !HOP(KEYWORDS, word)
 876                                 ? token("name", word)
 877                                 : HOP(OPERATORS, word)
 878                                 ? token("operator", word)
 879                                 : HOP(KEYWORDS_ATOM, word)
 880                                 ? token("atom", word)
 881                                 : token("keyword", word);
 882                 };
 883 
 884                 function with_eof_error(eof_error, cont) {
 885                         try {
 886                                 return cont();
 887                         } catch(ex) {
 888                                 if (ex === EX_EOF) parse_error(eof_error);
 889                                 else throw ex;
 890                         }
 891                 };
 892 
 893                 function next_token(force_regexp) {
 894                         if (force_regexp)
 895                                 return read_regexp();
 896                         skip_whitespace();
 897                         start_token();
 898                         var ch = peek();
 899                         if (!ch) return token("eof");
 900                         if (is_digit(ch)) return read_num();
 901                         if (ch == ‘"‘ || ch == "‘") return read_string();
 902                         if (HOP(PUNC_CHARS, ch)) return token("punc", next());
 903                         if (ch == ".") return handle_dot();
 904                         if (ch == "/") return handle_slash();
 905                         if (HOP(OPERATOR_CHARS, ch)) return read_operator();
 906                         if (ch == "\\" || is_identifier_start(ch)) return read_word();
 907                         parse_error("Unexpected character ‘" + ch + "‘");
 908                 };
 909 
 910                 next_token.context = function(nc) {
 911                         if (nc) S = nc;
 912                         return S;
 913                 };
 914 
 915                 return next_token;
 916 
 917         };
 918 
 919         /* -----[ Parser (constants) ]----- */
 920 
 921         var UNARY_PREFIX = array_to_hash([
 922                 "typeof",
 923                 "void",
 924                 "delete",
 925                 "--",
 926                 "++",
 927                 "!",
 928                 "~",
 929                 "-",
 930                 "+"
 931         ]);
 932 
 933         var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
 934 
 935         var ASSIGNMENT = (function(a, ret, i){
 936                 while (i < a.length) {
 937                         ret[a[i]] = a[i].substr(0, a[i].length - 1);
 938                         i++;
 939                 }
 940                 return ret;
 941         })(
 942                 ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="],
 943                 { "=": true },
 944                 0
 945         );
 946 
 947         var PRECEDENCE = (function(a, ret){
 948                 for (var i = 0, n = 1; i < a.length; ++i, ++n) {
 949                         var b = a[i];
 950                         for (var j = 0; j < b.length; ++j) {
 951                                 ret[b[j]] = n;
 952                         }
 953                 }
 954                 return ret;
 955         })(
 956                 [
 957                         ["||"],
 958                         ["&&"],
 959                         ["|"],
 960                         ["^"],
 961                         ["&"],
 962                         ["==", "===", "!=", "!=="],
 963                         ["<", ">", "<=", ">=", "in", "instanceof"],
 964                         [">>", "<<", ">>>"],
 965                         ["+", "-"],
 966                         ["*", "/", "%"]
 967                 ],
 968                 {}
 969         );
 970 
 971         var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
 972 
 973         var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
 974 
 975         /* -----[ Parser ]----- */
 976 
 977         function NodeWithToken(str, start, end) {
 978                 this.name = str;
 979                 this.start = start;
 980                 this.end = end;
 981         };
 982 
 983         NodeWithToken.prototype.toString = function() { return this.name; };
 984 
 985         function parse($TEXT, exigent_mode, embed_tokens) {
 986 
 987                 var S = {
 988                         input       : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
 989                         token       : null,
 990                         prev        : null,
 991                         peeked      : null,
 992                         in_function : 0,
 993                         in_loop     : 0,
 994                         labels      : []
 995                 };
 996 
 997                 S.token = next();
 998 
 999                 function is(type, value) {
1000                         return is_token(S.token, type, value);
1001                 };
1002 
1003                 function peek() { return S.peeked || (S.peeked = S.input()); };
1004 
1005                 function next() {
1006                         S.prev = S.token;
1007                         if (S.peeked) {
1008                                 S.token = S.peeked;
1009                                 S.peeked = null;
1010                         } else {
1011                                 S.token = S.input();
1012                         }
1013                         return S.token;
1014                 };
1015 
1016                 function prev() {
1017                         return S.prev;
1018                 };
1019 
1020                 function croak(msg, line, col, pos) {
1021                         var ctx = S.input.context();
1022                         js_error(msg,
1023                                  line != null ? line : ctx.tokline,
1024                                  col != null ? col : ctx.tokcol,
1025                                  pos != null ? pos : ctx.tokpos);
1026                 };
1027 
1028                 function token_error(token, msg) {
1029                         croak(msg, token.line, token.col);
1030                 };
1031 
1032                 function unexpected(token) {
1033                         if (token == null)
1034                                 token = S.token;
1035                         token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
1036                 };
1037 
1038                 function expect_token(type, val) {
1039                         if (is(type, val)) {
1040                                 return next();
1041                         }
1042                         token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
1043                 };
1044 
1045                 function expect(punc) { return expect_token("punc", punc); };
1046 
1047                 function can_insert_semicolon() {
1048                         return !exigent_mode && (
1049                                 S.token.nlb || is("eof") || is("punc", "}")
1050                         );
1051                 };
1052 
1053                 function semicolon() {
1054                         if (is("punc", ";")) next();
1055                         else if (!can_insert_semicolon()) unexpected();
1056                 };
1057 
1058                 function as() {
1059                         return slice(arguments);
1060                 };
1061 
1062                 function parenthesised() {
1063                         expect("(");
1064                         var ex = expression();
1065                         expect(")");
1066                         return ex;
1067                 };
1068 
1069                 function add_tokens(str, start, end) {
1070                         return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
1071                 };
1072 
1073                 var statement = embed_tokens ? function() {
1074                         var start = S.token;
1075                         var ast = $statement.apply(this, arguments);
1076                         ast[0] = add_tokens(ast[0], start, prev());
1077                         return ast;
1078                 } : $statement;
1079 
1080                 function $statement() {
1081                         if (is("operator", "/")) {
1082                                 S.peeked = null;
1083                                 S.token = S.input(true); // force regexp
1084                         }
1085                         switch (S.token.type) {
1086                             case "num":
1087                             case "string":
1088                             case "regexp":
1089                             case "operator":
1090                             case "atom":
1091                                 return simple_statement();
1092 
1093                             case "name":
1094                                 return is_token(peek(), "punc", ":")
1095                                         ? labeled_statement(prog1(S.token.value, next, next))
1096                                         : simple_statement();
1097 
1098                             case "punc":
1099                                 switch (S.token.value) {
1100                                     case "{":
1101                                         return as("block", block_());
1102                                     case "[":
1103                                     case "(":
1104                                         return simple_statement();
1105                                     case ";":
1106                                         next();
1107                                         return as("block");
1108                                     default:
1109                                         unexpected();
1110                                 }
1111 
1112                             case "keyword":
1113                                 switch (prog1(S.token.value, next)) {
1114                                     case "break":
1115                                         return break_cont("break");
1116 
1117                                     case "continue":
1118                                         return break_cont("continue");
1119 
1120                                     case "debugger":
1121                                         semicolon();
1122                                         return as("debugger");
1123 
1124                                     case "do":
1125                                         return (function(body){
1126                                                 expect_token("keyword", "while");
1127                                                 return as("do", prog1(parenthesised, semicolon), body);
1128                                         })(in_loop(statement));
1129 
1130                                     case "for":
1131                                         return for_();
1132 
1133                                     case "function":
1134                                         return function_(true);
1135 
1136                                     case "if":
1137                                         return if_();
1138 
1139                                     case "return":
1140                                         if (S.in_function == 0)
1141                                                 croak("‘return‘ outside of function");
1142                                         return as("return",
1143                                                   is("punc", ";")
1144                                                   ? (next(), null)
1145                                                   : can_insert_semicolon()
1146                                                   ? null
1147                                                   : prog1(expression, semicolon));
1148 
1149                                     case "switch":
1150                                         return as("switch", parenthesised(), switch_block_());
1151 
1152                                     case "throw":
1153                                         return as("throw", prog1(expression, semicolon));
1154 
1155                                     case "try":
1156                                         return try_();
1157 
1158                                     case "var":
1159                                         return prog1(var_, semicolon);
1160 
1161                                     case "const":
1162                                         return prog1(const_, semicolon);
1163 
1164                                     case "while":
1165                                         return as("while", parenthesised(), in_loop(statement));
1166 
1167                                     case "with":
1168                                         return as("with", parenthesised(), statement());
1169 
1170                                     default:
1171                                         unexpected();
1172                                 }
1173                         }
1174                 };
1175 
1176                 function labeled_statement(label) {
1177                         S.labels.push(label);
1178                         var start = S.token, stat = statement();
1179                         if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))
1180                                 unexpected(start);
1181                         S.labels.pop();
1182                         return as("label", label, stat);
1183                 };
1184 
1185                 function simple_statement() {
1186                         return as("stat", prog1(expression, semicolon));
1187                 };
1188 
1189                 function break_cont(type) {
1190                         var name = is("name") ? S.token.value : null;
1191                         if (name != null) {
1192                                 next();
1193                                 if (!member(name, S.labels))
1194                                         croak("Label " + name + " without matching loop or statement");
1195                         }
1196                         else if (S.in_loop == 0)
1197                                 croak(type + " not inside a loop or switch");
1198                         semicolon();
1199                         return as(type, name);
1200                 };
1201 
1202                 function for_() {
1203                         expect("(");
1204                         var init = null;
1205                         if (!is("punc", ";")) {
1206                                 init = is("keyword", "var")
1207                                         ? (next(), var_(true))
1208                                         : expression(true, true);
1209                                 if (is("operator", "in"))
1210                                         return for_in(init);
1211                         }
1212                         return regular_for(init);
1213                 };
1214 
1215                 function regular_for(init) {
1216                         expect(";");
1217                         var test = is("punc", ";") ? null : expression();
1218                         expect(";");
1219                         var step = is("punc", ")") ? null : expression();
1220                         expect(")");
1221                         return as("for", init, test, step, in_loop(statement));
1222                 };
1223 
1224                 function for_in(init) {
1225                         var lhs = init[0] == "var" ? as("name", init[1][0]) : init;
1226                         next();
1227                         var obj = expression();
1228                         expect(")");
1229                         return as("for-in", init, lhs, obj, in_loop(statement));
1230                 };
1231 
1232                 var function_ = embed_tokens ? function() {
1233                         var start = prev();
1234                         var ast = $function_.apply(this, arguments);
1235                         ast[0] = add_tokens(ast[0], start, prev());
1236                         return ast;
1237                 } : $function_;
1238 
1239                 function $function_(in_statement) {
1240                         var name = is("name") ? prog1(S.token.value, next) : null;
1241                         if (in_statement && !name)
1242                                 unexpected();
1243                         expect("(");
1244                         return as(in_statement ? "defun" : "function",
1245                                   name,
1246                                   // arguments
1247                                   (function(first, a){
1248                                           while (!is("punc", ")")) {
1249                                                   if (first) first = false; else expect(",");
1250                                                   if (!is("name")) unexpected();
1251                                                   a.push(S.token.value);
1252                                                   next();
1253                                           }
1254                                           next();
1255                                           return a;
1256                                   })(true, []),
1257                                   // body
1258                                   (function(){
1259                                           ++S.in_function;
1260                                           var loop = S.in_loop;
1261                                           S.in_loop = 0;
1262                                           var a = block_();
1263                                           --S.in_function;
1264                                           S.in_loop = loop;
1265                                           return a;
1266                                   })());
1267                 };
1268 
1269                 function if_() {
1270                         var cond = parenthesised(), body = statement(), belse;
1271                         if (is("keyword", "else")) {
1272                                 next();
1273                                 belse = statement();
1274                         }
1275                         return as("if", cond, body, belse);
1276                 };
1277 
1278                 function block_() {
1279                         expect("{");
1280                         var a = [];
1281                         while (!is("punc", "}")) {
1282                                 if (is("eof")) unexpected();
1283                                 a.push(statement());
1284                         }
1285                         next();
1286                         return a;
1287                 };
1288 
1289                 var switch_block_ = curry(in_loop, function(){
1290                         expect("{");
1291                         var a = [], cur = null;
1292                         while (!is("punc", "}")) {
1293                                 if (is("eof")) unexpected();
1294                                 if (is("keyword", "case")) {
1295                                         next();
1296                                         cur = [];
1297                                         a.push([ expression(), cur ]);
1298                                         expect(":");
1299                                 }
1300                                 else if (is("keyword", "default")) {
1301                                         next();
1302                                         expect(":");
1303                                         cur = [];
1304                                         a.push([ null, cur ]);
1305                                 }
1306                                 else {
1307                                         if (!cur) unexpected();
1308                                         cur.push(statement());
1309                                 }
1310                         }
1311                         next();
1312                         return a;
1313                 });
1314 
1315                 function try_() {
1316                         var body = block_(), bcatch, bfinally;
1317                         if (is("keyword", "catch")) {
1318                                 next();
1319                                 expect("(");
1320                                 if (!is("name"))
1321                                         croak("Name expected");
1322                                 var name = S.token.value;
1323                                 next();
1324                                 expect(")");
1325                                 bcatch = [ name, block_() ];
1326                         }
1327                         if (is("keyword", "finally")) {
1328                                 next();
1329                                 bfinally = block_();
1330                         }
1331                         if (!bcatch && !bfinally)
1332                                 croak("Missing catch/finally blocks");
1333                         return as("try", body, bcatch, bfinally);
1334                 };
1335 
1336                 function vardefs(no_in) {
1337                         var a = [];
1338                         for (;;) {
1339                                 if (!is("name"))
1340                                         unexpected();
1341                                 var name = S.token.value;
1342                                 next();
1343                                 if (is("operator", "=")) {
1344                                         next();
1345                                         a.push([ name, expression(false, no_in) ]);
1346                                 } else {
1347                                         a.push([ name ]);
1348                                 }
1349                                 if (!is("punc", ","))
1350                                         break;
1351                                 next();
1352                         }
1353                         return a;
1354                 };
1355 
1356                 function var_(no_in) {
1357                         return as("var", vardefs(no_in));
1358                 };
1359 
1360                 function const_() {
1361                         return as("const", vardefs());
1362                 };
1363 
1364                 function new_() {
1365                         var newexp = expr_atom(false), args;
1366                         if (is("punc", "(")) {
1367                                 next();
1368                                 args = expr_list(")");
1369                         } else {
1370                                 args = [];
1371                         }
1372                         return subscripts(as("new", newexp, args), true);
1373                 };
1374 
1375                 function expr_atom(allow_calls) {
1376                         if (is("operator", "new")) {
1377                                 next();
1378                                 return new_();
1379                         }
1380                         if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {
1381                                 return make_unary("unary-prefix",
1382                                                   prog1(S.token.value, next),
1383                                                   expr_atom(allow_calls));
1384                         }
1385                         if (is("punc")) {
1386                                 switch (S.token.value) {
1387                                     case "(":
1388                                         next();
1389                                         return subscripts(prog1(expression, curry(expect, ")")), allow_calls);
1390                                     case "[":
1391                                         next();
1392                                         return subscripts(array_(), allow_calls);
1393                                     case "{":
1394                                         next();
1395                                         return subscripts(object_(), allow_calls);
1396                                 }
1397                                 unexpected();
1398                         }
1399                         if (is("keyword", "function")) {
1400                                 next();
1401                                 return subscripts(function_(false), allow_calls);
1402                         }
1403                         if (HOP(ATOMIC_START_TOKEN, S.token.type)) {
1404                                 var atom = S.token.type == "regexp"
1405                                         ? as("regexp", S.token.value[0], S.token.value[1])
1406                                         : as(S.token.type, S.token.value);
1407                                 return subscripts(prog1(atom, next), allow_calls);
1408                         }
1409                         unexpected();
1410                 };
1411 
1412                 function expr_list(closing, allow_trailing_comma, allow_empty) {
1413                         var first = true, a = [];
1414                         while (!is("punc", closing)) {
1415                                 if (first) first = false; else expect(",");
1416                                 if (allow_trailing_comma && is("punc", closing)) break;
1417                                 if (is("punc", ",") && allow_empty) {
1418                                         a.push([ "atom", "undefined" ]);
1419                                 } else {
1420                                         a.push(expression(false));
1421                                 }
1422                         }
1423                         next();
1424                         return a;
1425                 };
1426 
1427                 function array_() {
1428                         return as("array", expr_list("]", !exigent_mode, true));
1429                 };
1430 
1431                 function object_() {
1432                         var first = true, a = [];
1433                         while (!is("punc", "}")) {
1434                                 if (first) first = false; else expect(",");
1435                                 if (!exigent_mode && is("punc", "}"))
1436                                         // allow trailing comma
1437                                         break;
1438                                 var type = S.token.type;
1439                                 var name = as_property_name();
1440                                 if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
1441                                         a.push([ as_name(), function_(false), name ]);
1442                                 } else {
1443                                         expect(":");
1444                                         a.push([ name, expression(false) ]);
1445                                 }
1446                         }
1447                         next();
1448                         return as("object", a);
1449                 };
1450 
1451                 function as_property_name() {
1452                         switch (S.token.type) {
1453                             case "num":
1454                             case "string":
1455                                 return prog1(S.token.value, next);
1456                         }
1457                         return as_name();
1458                 };
1459 
1460                 function as_name() {
1461                         switch (S.token.type) {
1462                             case "name":
1463                             case "operator":
1464                             case "keyword":
1465                             case "atom":
1466                                 return prog1(S.token.value, next);
1467                             default:
1468                                 unexpected();
1469                         }
1470                 };
1471 
1472                 function subscripts(expr, allow_calls) {
1473                         if (is("punc", ".")) {
1474                                 next();
1475                                 return subscripts(as("dot", expr, as_name()), allow_calls);
1476                         }
1477                         if (is("punc", "[")) {
1478                                 next();
1479                                 return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);
1480                         }
1481                         if (allow_calls && is("punc", "(")) {
1482                                 next();
1483                                 return subscripts(as("call", expr, expr_list(")")), true);
1484                         }
1485                         if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) {
1486                                 return prog1(curry(make_unary, "unary-postfix", S.token.value, expr),
1487                                              next);
1488                         }
1489                         return expr;
1490                 };
1491 
1492                 function make_unary(tag, op, expr) {
1493                         if ((op == "++" || op == "--") && !is_assignable(expr))
1494                                 croak("Invalid use of " + op + " operator");
1495                         return as(tag, op, expr);
1496                 };
1497 
1498                 function expr_op(left, min_prec, no_in) {
1499                         var op = is("operator") ? S.token.value : null;
1500                         if (op && op == "in" && no_in) op = null;
1501                         var prec = op != null ? PRECEDENCE[op] : null;
1502                         if (prec != null && prec > min_prec) {
1503                                 next();
1504                                 var right = expr_op(expr_atom(true), prec, no_in);
1505                                 return expr_op(as("binary", op, left, right), min_prec, no_in);
1506                         }
1507                         return left;
1508                 };
1509 
1510                 function expr_ops(no_in) {
1511                         return expr_op(expr_atom(true), 0, no_in);
1512                 };
1513 
1514                 function maybe_conditional(no_in) {
1515                         var expr = expr_ops(no_in);
1516                         if (is("operator", "?")) {
1517                                 next();
1518                                 var yes = expression(false);
1519                                 expect(":");
1520                                 return as("conditional", expr, yes, expression(false, no_in));
1521                         }
1522                         return expr;
1523                 };
1524 
1525                 function is_assignable(expr) {
1526                         if (!exigent_mode) return true;
1527                         switch (expr[0]) {
1528                             case "dot":
1529                             case "sub":
1530                             case "new":
1531                             case "call":
1532                                 return true;
1533                             case "name":
1534                                 return expr[1] != "this";
1535                         }
1536                 };
1537 
1538                 function maybe_assign(no_in) {
1539                         var left = maybe_conditional(no_in), val = S.token.value;
1540                         if (is("operator") && HOP(ASSIGNMENT, val)) {
1541                                 if (is_assignable(left)) {
1542                                         next();
1543                                         return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in));
1544                                 }
1545                                 croak("Invalid assignment");
1546                         }
1547                         return left;
1548                 };
1549 
1550                 function expression(commas, no_in) {
1551                         if (arguments.length == 0)
1552                                 commas = true;
1553                         var expr = maybe_assign(no_in);
1554                         if (commas && is("punc", ",")) {
1555                                 next();
1556                                 return as("seq", expr, expression(true, no_in));
1557                         }
1558                         return expr;
1559                 };
1560 
1561                 function in_loop(cont) {
1562                         try {
1563                                 ++S.in_loop;
1564                                 return cont();
1565                         } finally {
1566                                 --S.in_loop;
1567                         }
1568                 };
1569 
1570                 return as("toplevel", (function(a){
1571                         while (!is("eof"))
1572                                 a.push(statement());
1573                         return a;
1574                 })([]));
1575 
1576         };
1577 
1578         /* -----[ Utilities ]----- */
1579 
1580         function curry(f) {
1581                 var args = slice(arguments, 1);
1582                 return function() { return f.apply(this, args.concat(slice(arguments))); };
1583         };
1584 
1585         function prog1(ret) {
1586                 if (ret instanceof Function)
1587                         ret = ret();
1588                 for (var i = 1, n = arguments.length; --n > 0; ++i)
1589                         arguments[i]();
1590                 return ret;
1591         };
1592 
1593         function array_to_hash(a) {
1594                 var ret = {};
1595                 for (var i = 0; i < a.length; ++i)
1596                         ret[a[i]] = true;
1597                 return ret;
1598         };
1599 
1600         function slice(a, start) {
1601                 return Array.prototype.slice.call(a, start == null ? 0 : start);
1602         };
1603 
1604         function characters(str) {
1605                 return str.split("");
1606         };
1607 
1608         function member(name, array) {
1609                 for (var i = array.length; --i >= 0;)
1610                         if (array[i] === name)
1611                                 return true;
1612                 return false;
1613         };
1614 
1615         function HOP(obj, prop) {
1616                 return Object.prototype.hasOwnProperty.call(obj, prop);
1617         };
1618 
1619         var warn = function() {};
1620 
1621         return parse;
1622 
1623     })();
1624     
1625     var Wind;
1626     
1627     var codeGenerator = (typeof eval("(function () {})") == "function") ?
1628         function (code) { return code; } :
1629         function (code) { return "false || " + code; };
1630         
1631     // support string type only.
1632     var stringify = (typeof JSON !== "undefined" && JSON.stringify) ?
1633         function (s) { return JSON.stringify(s); } :
1634         (function () {
1635             // Implementation comes from JSON2 (http://www.json.org/js.html)
1636         
1637             var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
1638             
1639             var meta = {    // table of character substitutions
1640                 ‘\b‘: ‘\\b‘,
1641                 ‘\t‘: ‘\\t‘,
1642                 ‘\n‘: ‘\\n‘,
1643                 ‘\f‘: ‘\\f‘,
1644                 ‘\r‘: ‘\\r‘,
1645                 ‘"‘ : ‘\\"‘,
1646                 ‘\\‘: ‘\\\\‘
1647             }
1648             
1649             return function (s) {
1650                 // If the string contains no control characters, no quote characters, and no
1651                 // backslash characters, then we can safely slap some quotes around it.
1652                 // Otherwise we must also replace the offending characters with safe escape
1653                 // sequences.
1654 
1655                 escapable.lastIndex = 0;
1656                 return escapable.test(s) ? ‘"‘ + s.replace(escapable, function (a) {
1657                     var c = meta[a];
1658                     return typeof c === ‘s‘ ? c :
1659                         ‘\\u‘ + (‘0000‘ + a.charCodeAt(0).toString(16)).slice(-4);
1660                 }) + ‘"‘ : ‘"‘ + s + ‘"‘;
1661             };
1662         })();
1663     
1664     function sprintf(format) {
1665         var args = arguments;
1666         return format.toString().replace(new RegExp("{\\d+}", "g"), function (p) {
1667             var n = parseInt(p.substring(1, p.length - 1), 10);
1668             return args[n + 1];
1669         });
1670     }
1671     
1672     function trim(s) {
1673         return s.replace(/ +/g, "");
1674     }
1675 
1676     function getPrecedence(ast) {
1677         var type = ast[0];
1678         switch (type) {
1679             case "dot": // .
1680             case "sub": // []
1681             case "call": // ()
1682                 return 1;
1683             case "unary-postfix": // ++ -- - ~ ! delete new typeof void
1684             case "unary-prefix":
1685                 return 2;
1686             case "var":
1687             case "binary":
1688                 switch (ast[1]) {
1689                     case "*":
1690                     case "/":
1691                     case "%":
1692                         return 3;
1693                     case "+":
1694                     case "-":
1695                         return 4;
1696                     case "<<":
1697                     case ">>":
1698                     case ">>>":
1699                         return 5;
1700                     case "<":
1701                     case "<=":
1702                     case ">":
1703                     case ">=":
1704                     case "instanceof":
1705                         return 6;
1706                     case "==":
1707                     case "!=":
1708                     case "===":
1709                     case "!==":
1710                         return 7;
1711                     case "&":
1712                         return 8;
1713                     case "^":
1714                         return 9;
1715                     case "|":
1716                         return 10;
1717                     case "&&":
1718                         return 11;
1719                     case "||":
1720                         return 12;
1721                 }
1722             case "conditional":
1723                 return 13;
1724             case "assign":
1725                 return 14;
1726             case "new":
1727                 return 15;
1728             case "seq":
1729             case "stat":
1730             case "name":
1731             case "object":
1732             case "array":
1733             case "num":
1734             case "regexp":
1735             case "string":
1736             case "function":
1737             case "defun":
1738             case "for":
1739             case "for-in":
1740             case "block":
1741             case "while":
1742             case "do":
1743             case "if":
1744             case "break":
1745             case "continue":
1746             case "return":
1747             case "throw":
1748             case "try":
1749             case "switch": 
1750                 return 0;
1751             default:
1752                 return 100; // the lowest
1753         }
1754     }
1755 
1756     var CodeWriter = function (indent) {
1757         this._indent = indent || "    ";
1758         this._indentLevel = 0;
1759         
1760         this.lines = [];
1761     }
1762     CodeWriter.prototype = {
1763         write: function (str) {
1764             if (str === undefined) return;
1765             
1766             if (this.lines.length == 0) {
1767                 this.lines.push("");
1768             }
1769 
1770             this.lines[this.lines.length - 1] += str;
1771             return this;
1772         },
1773         
1774         writeLine: function () {
1775             this.write.apply(this, arguments);
1776             this.lines.push("");
1777             return this;
1778         },
1779         
1780         writeIndents: function () {
1781             var indents = new Array(this._indentLevel);
1782             for (var i = 0; i < this._indentLevel; i++) {
1783                 indents[i] = this._indent;
1784             }
1785             
1786             this.write(indents.join(""));
1787             return this;
1788         }, 
1789         
1790         addIndentLevel: function (diff) {
1791             this._indentLevel += diff;
1792             return this;
1793         }
1794     };
1795     
1796     var SeedProvider = function () {
1797         this._seeds = {};
1798     }
1799     SeedProvider.prototype.next = function (key) {
1800         var value = this._seeds[key];
1801         if (value == undefined) {
1802             this._seeds[key] = 0;
1803             return 0;
1804         } else {
1805             this._seeds[key] = ++value;
1806             return value;
1807         }
1808     }
1809     
1810     function isWindPattern(ast) {
1811         if (ast[0] != "call") return false;
1812         
1813         var evalName = ast[1];
1814         if (evalName[0] != "name" || evalName[1] != "eval") return false;
1815 
1816         var compileCall = ast[2][0];
1817         if (!compileCall || compileCall[0] != "call") return false;
1818 
1819         var compileMethod = compileCall[1];
1820         if (!compileMethod || compileMethod[0] != "dot" || compileMethod[2] != "compile") return false;
1821 
1822         var windName = compileMethod[1];
1823         if (!windName || windName[0] != "name" || windName[1] != compile.rootName) return false;
1824 
1825         var builder = compileCall[2][0];
1826         if (!builder || builder[0] != "string") return false;
1827 
1828         var func = compileCall[2][1];
1829         if (!func || func[0] != "function") return false;
1830 
1831         return true;
1832     }
1833     
1834     function compileWindPattern(ast, seedProvider, codeWriter, commentWriter) {
1835 
1836         var builderName = ast[2][0][2][0][1];
1837         var funcAst = ast[2][0][2][1];
1838 
1839         var windTreeGenerator = new WindTreeGenerator(builderName, seedProvider);
1840         var windAst = windTreeGenerator.generate(funcAst);
1841 
1842         commentWriter.write(builderName + " << ");
1843         var codeGenerator = new CodeGenerator(builderName, seedProvider, codeWriter, commentWriter);
1844         
1845         var funcName = funcAst[1] || "";
1846         codeGenerator.generate(funcName, funcAst[2], windAst);
1847         
1848         return funcName;
1849     }
1850         
1851     var WindTreeGenerator = function (builderName, seedProvider) {
1852         this._binder = Wind.binders[builderName];
1853         this._seedProvider = seedProvider;
1854     }
1855     WindTreeGenerator.prototype = {
1856 
1857         generate: function (ast) {
1858 
1859             var params = ast[2], statements = ast[3];
1860 
1861             var rootAst = { type: "delay", stmts: [] };
1862 
1863             this._visitStatements(statements, rootAst.stmts);
1864 
1865             return rootAst;
1866         },
1867 
1868         _getBindInfo: function (stmt) {
1869 
1870             var type = stmt[0];
1871             if (type == "stat") {
1872                 var expr = stmt[1];
1873                 if (expr[0] == "call") {
1874                     var callee = expr[1];
1875                     if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
1876                         return {
1877                             expression: expr[2][0],
1878                             argName: "",
1879                             assignee: null
1880                         };
1881                     }
1882                 } else if (expr[0] == "assign") {
1883                     var assignee = expr[2];
1884                     expr = expr[3];
1885                     if (expr[0] == "call") {
1886                         var callee = expr[1];
1887                         if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
1888                             return {
1889                                 expression: expr[2][0],
1890                                 argName: "_result_$",
1891                                 assignee: assignee
1892                             };
1893                         }
1894                     }
1895                 }
1896             } else if (type == "var") {
1897                 var defs = stmt[1];
1898                 if (defs.length == 1) {
1899                     var item = defs[0];
1900                     var name = item[0];
1901                     var expr = item[1];
1902                     if (expr && expr[0] == "call") {
1903                         var callee = expr[1];
1904                         if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
1905                             return {
1906                                 expression: expr[2][0],
1907                                 argName: name,
1908                                 assignee: null
1909                             };                            
1910                         }
1911                     }
1912                 }
1913             } else if (type == "return") {
1914                 var expr = stmt[1];
1915                 if (expr && expr[0] == "call") {
1916                     var callee = expr[1];
1917                     if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
1918                         return {
1919                             expression: expr[2][0],
1920                             argName: "_result_$",
1921                             assignee: "return"
1922                         };
1923                     }
1924                 }
1925             }
1926 
1927             return null;
1928         },
1929 
1930         _visitStatements: function (statements, stmts, index) {
1931             if (arguments.length <= 2) index = 0;
1932 
1933             if (index >= statements.length) {
1934                 stmts.push({ type: "normal" });
1935                 return this;
1936             }
1937 
1938             var currStmt = statements[index];
1939             var bindInfo = this._getBindInfo(currStmt);
1940 
1941             if (bindInfo) {
1942                 var bindStmt = { type: "bind", info: bindInfo };
1943                 stmts.push(bindStmt);
1944 
1945                 if (bindInfo.assignee != "return") {
1946                     bindStmt.stmts = [];
1947                     this._visitStatements(statements, bindStmt.stmts, index + 1);
1948                 }
1949 
1950             } else {
1951                 var type = currStmt[0];
1952                 if (type == "return" || type == "break" || type == "continue" || type == "throw") {
1953 
1954                     stmts.push({ type: type, stmt: currStmt });
1955 
1956                 } else if (type == "if" || type == "try" || type == "for" || type == "do"
1957                            || type == "while" || type == "switch" || type == "for-in") {
1958 
1959                     var newStmt = this._visit(currStmt);
1960 
1961                     if (newStmt.type == "raw") {
1962                         stmts.push(newStmt);
1963                         this._visitStatements(statements, stmts, index + 1);
1964                     } else {
1965                         var isLast = (index == statements.length - 1);
1966                         if (isLast) {
1967                             stmts.push(newStmt);
1968                         } else {
1969 
1970                             var combineStmt = {
1971                                 type: "combine",
1972                                 first: { type: "delay", stmts: [newStmt] },
1973                                 second: { type: "delay", stmts: [] }
1974                             };
1975                             stmts.push(combineStmt);
1976 
1977                             this._visitStatements(statements, combineStmt.second.stmts, index + 1);
1978                         }
1979                     }
1980 
1981                 } else {
1982 
1983                     stmts.push({ type: "raw", stmt: currStmt });
1984 
1985                     this._visitStatements(statements, stmts, index + 1);
1986                 }
1987             }
1988 
1989             return this;
1990         },
1991 
1992         _visit: function (ast) {
1993 
1994             var type = ast[0];
1995 
1996             function throwUnsupportedError() {
1997                 throw new Error(‘"‘ + type + ‘" is not currently supported.‘);
1998             }
1999 
2000             var visitor = this._visitors[type];
2001 
2002             if (visitor) {
2003                 return visitor.call(this, ast);
2004             } else {
2005                 throwUnsupportedError();
2006             }
2007         },
2008 
2009         _visitBody: function (ast, stmts) {
2010             if (ast[0] == "block") {
2011                 this._visitStatements(ast[1], stmts);
2012             } else {
2013                 this._visitStatements([ast], stmts);
2014             }
2015         },
2016 
2017         _noBinding: function (stmts) {
2018             switch (stmts[stmts.length - 1].type) {
2019                 case "normal":
2020                 case "return":
2021                 case "break":
2022                 case "throw":
2023                 case "continue":
2024                     return true;
2025             }
2026 
2027             return false;
2028         },
2029 
2030         _collectCaseStatements: function (cases, index) {
2031             var res = [];
2032 
2033             for (var i = index; i < cases.length; i++) {
2034                 var rawStmts = cases[i][1];
2035                 for (var j = 0; j < rawStmts.length; j++) {
2036                     if (rawStmts[j][0] == "break") {
2037                         return res
2038                     }
2039 
2040                     res.push(rawStmts[j]);
2041                 }
2042             }
2043 
2044             return res;
2045         },
2046 
2047         _visitors: {
2048 
2049             "for": function (ast) {
2050                 var bodyStmts = [];
2051                 var body = ast[4];
2052                 this._visitBody(body, bodyStmts);
2053 
2054                 if (this._noBinding(bodyStmts)) {
2055                     return { type: "raw", stmt: ast };
2056                 }
2057                 
2058                 var delayStmt = { type: "delay", stmts: [] };
2059                 
2060                 var setup = ast[1];
2061                 if (setup) {
2062                     delayStmt.stmts.push({ type: "raw", stmt: setup });
2063                 }
2064                 
2065                 var forStmt = { type: "for", bodyStmt: { type: "delay", stmts: bodyStmts } };
2066                 delayStmt.stmts.push(forStmt);
2067                 
2068                 var condition = ast[2];
2069                 if (condition) {
2070                     forStmt.condition = condition;
2071                 }
2072                 
2073                 var update = ast[3];
2074                 if (update) {
2075                     forStmt.update = update;
2076                 }
2077 
2078                 return delayStmt;
2079             },
2080             
2081             "for-in": function (ast) {
2082 
2083                 var body = ast[4];
2084                 
2085                 var bodyStmts = [];
2086                 this._visitBody(body, bodyStmts);
2087 
2088                 if (this._noBinding(bodyStmts)) {
2089                     return { type: "raw", stmt: ast };
2090                 }
2091                 
2092                 var forInStmt = { type: "for-in", bodyStmts: bodyStmts, obj: ast[3] };
2093             
2094                 var argName = ast[2][1]; // ast[2] == ["name", m]
2095                 if (ast[1][0] == "var") {
2096                     forInStmt.argName = argName;
2097                 } else {
2098                     var keyVar = "_forInKey_$" + this._seedProvider.next("forInKey");
2099                     forInStmt.argName = keyVar;
2100                     forInStmt.bodyStmts.unshift({
2101                         type: "raw",
2102                         stmt: parse(argName + " = " + keyVar + ";")[1][0]
2103                     });
2104                 }
2105             
2106                 return forInStmt;
2107             },
2108         
2109             "while": function (ast) {
2110 
2111                 var bodyStmts = [];
2112                 var body = ast[2];
2113                 this._visitBody(body, bodyStmts);
2114 
2115                 if (this._noBinding(bodyStmts)) {
2116                     return { type: "raw", stmt: ast }
2117                 }
2118 
2119                 var loopStmt = { type: "while", bodyStmt: { type: "delay", stmts: bodyStmts } };
2120 
2121                 var condition = ast[1];
2122                 loopStmt.condition = condition;
2123 
2124                 return loopStmt;
2125             },
2126             
2127             "do": function (ast) {
2128 
2129                 var bodyStmts = [];
2130                 var body = ast[2];
2131                 this._visitBody(body, bodyStmts);
2132 
2133                 if (this._noBinding(bodyStmts)) {
2134                     return { type: "raw", stmt: ast };
2135                 }
2136 
2137                 var doStmt = {
2138                     type: "do",
2139                     bodyStmt: { type: "delay", stmts: bodyStmts },
2140                     condition: ast[1]
2141                 };
2142 
2143                 return doStmt;
2144             },
2145 
2146             "switch": function (ast) {
2147                 var noBinding = true;
2148 
2149                 var switchStmt = { type: "switch", item: ast[1], caseStmts: [] };
2150 
2151                 var cases = ast[2];
2152                 for (var i = 0; i < cases.length; i++) {                    
2153                     var caseStmt = { item: cases[i][0], stmts: [] };
2154                     switchStmt.caseStmts.push(caseStmt);
2155 
2156                     var statements = this._collectCaseStatements(cases, i);
2157                     this._visitStatements(statements, caseStmt.stmts);
2158                     noBinding = noBinding && this._noBinding(caseStmt.stmts);
2159                 }
2160 
2161                 if (noBinding) {
2162                     return { type: "raw", stmt: ast };
2163                 } else {
2164                     return switchStmt;
2165                 }
2166             },
2167 
2168             "if": function (ast) {
2169 
2170                 var noBinding = true;
2171 
2172                 var ifStmt = { type: "if", conditionStmts: [] };
2173 
2174                 var currAst = ast;
2175                 while (true) {
2176                     var condition = currAst[1];
2177                     var condStmt = { cond: condition, stmts: [] };
2178                     ifStmt.conditionStmts.push(condStmt);
2179 
2180                     var thenPart = currAst[2];
2181                     this._visitBody(thenPart, condStmt.stmts);
2182 
2183                     noBinding = noBinding && this._noBinding(condStmt.stmts);
2184 
2185                     var elsePart = currAst[3];
2186                     if (elsePart && elsePart[0] == "if") {
2187                         currAst = elsePart;
2188                     } else {
2189                         break;
2190                     }
2191                 }
2192     
2193                 var elsePart = currAst[3];
2194                 if (elsePart) {
2195                     ifStmt.elseStmts = [];
2196 
2197                     this._visitBody(elsePart, ifStmt.elseStmts);
2198                     
2199                     noBinding = noBinding && this._noBinding(ifStmt.elseStmts);
2200                 }
2201 
2202                 if (noBinding) {
2203                     return { type: "raw", stmt: ast };
2204                 } else {
2205                     return ifStmt;
2206                 }
2207             },
2208 
2209             "try": function (ast, stmts) {
2210 
2211                 var bodyStmts = [];
2212                 var bodyStatements = ast[1];
2213                 this._visitStatements(bodyStatements, bodyStmts);
2214 
2215                 var noBinding = this._noBinding(bodyStmts)
2216 
2217                 var tryStmt = { type: "try", bodyStmt: { type: "delay", stmts: bodyStmts } };
2218                 
2219                 var catchClause = ast[2];
2220                 if (catchClause) {
2221                     var exVar = catchClause[0];
2222                     tryStmt.exVar = exVar;
2223                     tryStmt.catchStmts = [];
2224 
2225                     this._visitStatements(catchClause[1], tryStmt.catchStmts);
2226 
2227                     noBinding = noBinding && this._noBinding(tryStmt.catchStmts);
2228                 }
2229 
2230                 var finallyStatements = ast[3];
2231                 if (finallyStatements) {
2232                     tryStmt.finallyStmt = { type: "delay", stmts: [] };
2233 
2234                     this._visitStatements(finallyStatements, tryStmt.finallyStmt.stmts);
2235 
2236                     noBinding = noBinding && this._noBinding(tryStmt.finallyStmt.stmts);
2237                 }
2238 
2239                 if (noBinding) {
2240                     return { type: "raw", stmt: ast };
2241                 } else {
2242                     return tryStmt;
2243                 }
2244             }
2245         }
2246     }
2247     
2248     var CodeGenerator = function (builderName, seedProvider, codeWriter, commentWriter) {
2249         this._builderName = builderName;
2250         this._binder = Wind.binders[builderName];
2251         this._seedProvider = seedProvider;
2252         
2253         this._codeWriter = codeWriter;
2254         this._commentWriter = commentWriter;
2255     }
2256     CodeGenerator.prototype = {
2257     
2258         _code: function () {
2259             this._codeWriter.write.apply(this._codeWriter, arguments);
2260             return this;
2261         },
2262         
2263         _codeLine: function () {
2264             this._codeWriter.writeLine.apply(this._codeWriter, arguments);
2265             return this;
2266         },
2267         
2268         _codeIndents: function () {
2269             this._codeWriter.writeIndents();
2270             return this;
2271         },
2272         
2273         _codeIndentLevel: function (diff) {
2274             this._codeWriter.addIndentLevel(diff);
2275             return this;
2276         },
2277         
2278         _comment: function () {
2279             this._commentWriter.write.apply(this._commentWriter, arguments);
2280             return this;
2281         },
2282         
2283         _commentLine: function () {
2284             this._commentWriter.writeLine.apply(this._commentWriter, arguments);
2285             return this;
2286         },
2287         
2288         _commentIndents: function () {
2289             this._commentWriter.writeIndents();
2290             return this;
2291         },
2292         
2293         _commentIndentLevel: function (diff) {
2294             this._commentWriter.addIndentLevel(diff);
2295             return this;
2296         },
2297         
2298         _both: function () {
2299             this._codeWriter.write.apply(this._codeWriter, arguments);
2300             this._commentWriter.write.apply(this._commentWriter, arguments);
2301 
2302             return this;
2303         },
2304         
2305         _bothLine: function () {
2306             this._codeWriter.writeLine.apply(this._codeWriter, arguments);
2307             this._commentWriter.writeLine.apply(this._commentWriter, arguments);
2308             
2309             return this;
2310         },
2311         
2312         _bothIndents: function () {
2313             this._codeWriter.writeIndents();
2314             this._commentWriter.writeIndents();
2315             
2316             return this;
2317         },
2318         
2319         _bothIndentLevel: function (diff) {
2320             this._codeWriter.addIndentLevel(diff);
2321             this._commentWriter.addIndentLevel(diff);
2322             
2323             return this;
2324         },
2325         
2326         _newLine: function () {
2327             this._codeWriter.writeLine.apply(this._codeWriter, arguments);
2328             this._commentWriter.writeLine(); // To Remove
2329             return this;
2330         },
2331     
2332         generate: function (name, params, windAst) {
2333             this._normalMode = false;
2334             this._builderVar = "_builder_$" + this._seedProvider.next("builderId");
2335             
2336             this._codeLine("(function " + name + "(" + params.join(", ") + ") {")._commentLine("function (" + params.join(", ") + ") {");
2337             this._bothIndentLevel(1);
2338 
2339             this._codeIndents()._newLine("var " + this._builderVar + " = " + compile.rootName + ".builders[" + stringify(this._builderName) + "];");
2340 
2341             this._codeIndents()._newLine("return " + this._builderVar + ".Start(this,");
2342             this._codeIndentLevel(1);
2343 
2344             this._pos = { };
2345 
2346             this._bothIndents()._visitWind(windAst)._newLine();
2347             this._codeIndentLevel(-1);
2348 
2349             this._codeIndents()._newLine(");");
2350             this._bothIndentLevel(-1);
2351 
2352             this._bothIndents()._code("})")._comment("}");
2353         },
2354 
2355         _visitWind: function (ast) {
2356             this._windVisitors[ast.type].call(this, ast);
2357             return this;
2358         },
2359 
2360         _visitRaw: function (ast) {
2361             var type = ast[0];
2362 
2363             var visitor = this._rawVisitors[type];
2364             if (visitor) {
2365                 visitor.call(this, ast);
2366             } else {
2367                 throw new Error(‘"‘ + type + ‘" is not currently supported.‘);
2368             }
2369 
2370             return this;
2371         },
2372 
2373         _visitWindStatements: function (statements) {
2374             for (var i = 0; i < statements.length; i++) {
2375                 var stmt = statements[i];
2376 
2377                 if (stmt.type == "raw" || stmt.type == "if" || stmt.type == "switch") {
2378                     this._bothIndents()._visitWind(stmt)._newLine();
2379                 } else if (stmt.type == "delay") {
2380                     this._visitWindStatements(stmt.stmts);
2381                 } else {
2382                     this._bothIndents()._code("return ")._visitWind(stmt)._newLine(";");
2383                 }
2384             }
2385         },
2386 
2387         _visitRawStatements: function (statements) {
2388             for (var i = 0; i < statements.length; i++) {
2389                 var s = statements[i];
2390 
2391                 this._bothIndents()._visitRaw(s)._bothLine();
2392 
2393                 switch (s[0]) {
2394                     case "break":
2395                     case "return":
2396                     case "continue":
2397                     case "throw":
2398                         return;
2399                 }
2400             }
2401         },
2402 
2403         _visitRawBody: function (body) {
2404             if (body[0] == "block") {
2405                 this._visitRaw(body);
2406             } else {
2407                 this._bothLine();
2408                 this._bothIndentLevel(1);
2409 
2410                 this._bothIndents()._visitRaw(body);
2411                 this._bothIndentLevel(-1);
2412             }
2413 
2414             return this;
2415         },
2416 
2417         _visitRawFunction: function (ast) {
2418             var funcName = ast[1] || "";
2419             var args = ast[2];
2420             var statements = ast[3];
2421             
2422             this._bothLine("function " + funcName + "(" + args.join(", ") + ") {")
2423             this._bothIndentLevel(1);
2424 
2425             var currInFunction = this._pos.inFunction;
2426             this._pos.inFunction = true;
2427 
2428             this._visitRawStatements(statements);
2429             this._bothIndentLevel(-1);
2430 
2431             this._pos.inFunction = currInFunction;
2432 
2433             this._bothIndents()._both("}");
2434         },
2435         
2436         _windVisitors: {
2437             "delay": function (ast) {
2438                 if (ast.stmts.length == 1) {
2439                     var subStmt = ast.stmts[0];
2440                     switch (subStmt.type) {
2441                         case "delay":
2442                         case "combine":
2443                         case "normal":
2444                         case "break":
2445                         case "continue":
2446                         case "for":
2447                         case "for-in":
2448                         case "while":
2449                         case "do":
2450                         case "try":
2451                             this._visitWind(subStmt);
2452                             return;
2453                         case "return":
2454                             if (!subStmt.stmt[1]) {
2455                                 this._visitWind(subStmt);
2456                                 return;
2457                             }
2458                     }
2459                 }
2460 
2461                 this._newLine(this._builderVar + ".Delay(function () {");
2462                 this._codeIndentLevel(1);
2463 
2464                 this._visitWindStatements(ast.stmts);
2465                 this._codeIndentLevel(-1);
2466 
2467                 this._codeIndents()._code("})");
2468             },
2469 
2470             "combine": function (ast) {
2471                 this._newLine(this._builderVar + ".Combine(");
2472                 this._codeIndentLevel(1);
2473 
2474                 this._bothIndents()._visitWind(ast.first)._newLine(",");
2475                 this._bothIndents()._visitWind(ast.second)._newLine();
2476                 this._codeIndentLevel(-1);
2477 
2478                 this._codeIndents()._code(")");
2479             },
2480             
2481             "for": function (ast) {                
2482                 if (ast.condition) {
2483                     this._codeLine(this._builderVar + ".For(function () {")
2484                         ._commentLine("for (");
2485                     this._codeIndentLevel(1);
2486                     
2487                     this._bothIndents()
2488                         ._code("return ")
2489                         ._comment("; ")
2490                             ._visitRaw(ast.condition)
2491                                 ._newLine(";");
2492                     this._codeIndentLevel(-1);
2493                     
2494                     this._bothIndents()._code("}, ");
2495                 } else {
2496                     this._code(this._builderVar + ".For(null, ")
2497                         ._comment("for (; ");
2498                 }
2499                 
2500                 if (ast.update) {
2501                     this._newLine("function () {");
2502                     this._codeIndentLevel(1);
2503                     
2504                     this._bothIndents()
2505                         ._comment("; ")
2506                             ._visitRaw(ast.update)
2507                                 ._codeLine(";")
2508                                 ._commentLine(") {");
2509                     this._codeIndentLevel(-1);
2510                     
2511                     this._codeIndents()._newLine("},");
2512                 } else {
2513                     this._codeLine("null,")._commentLine("; ) {");
2514                 }
2515                 this._bothIndentLevel(1);
2516                 
2517                 this._bothIndents()._visitWind(ast.bodyStmt)._newLine();
2518                 this._bothIndentLevel(-1);
2519                 
2520                 this._bothIndents()._code(")")._comment("}");
2521             },
2522             
2523             "for-in": function (ast) {
2524                 this._code(this._builderVar + ".ForIn(")
2525                     ._comment("for (var " + ast.argName + " in ")
2526                         ._visitRaw(ast.obj)
2527                             ._codeLine(", function (" + ast.argName + ") {")
2528                             ._commentLine(") {");
2529                 this._bothIndentLevel(1);
2530                 
2531                 this._visitWindStatements(ast.bodyStmts);
2532                 this._bothIndentLevel(-1);
2533                 
2534                 this._bothIndents()._code("})")._comment("}");
2535             },
2536             
2537             "while": function (ast) {
2538                 this._newLine(this._builderVar + ".While(function () {");
2539                 this._codeIndentLevel(1);
2540                 
2541                 this._bothIndents()
2542                     ._code("return ")
2543                     ._comment("while (")
2544                         ._visitRaw(ast.condition)
2545                             ._codeLine(";")
2546                             ._commentLine(") {");
2547                 this._codeIndentLevel(-1);
2548                 
2549                 this._codeIndents()._newLine("},");
2550                 this._bothIndentLevel(1);
2551                 
2552                 this._bothIndents()._visitWind(ast.bodyStmt)._newLine();
2553                 this._bothIndentLevel(-1);
2554                 
2555                 this._bothIndents()._code(")")._comment("}");
2556             },
2557             
2558             "do": function (ast) {
2559                 this._codeLine(this._builderVar + ".Do(")._commentLine("do {");
2560                 this._bothIndentLevel(1);
2561                 
2562                 this._bothIndents()._visitWind(ast.bodyStmt)._newLine(",");
2563                 this._commentIndentLevel(-1);
2564                 
2565                 this._codeIndents()._newLine("function () {");
2566                 this._codeIndentLevel(1);
2567                 
2568                 this._bothIndents()
2569                     ._code("return ")
2570                     ._comment("} while (")
2571                         ._visitRaw(ast.condition)
2572                             ._codeLine(";")
2573                             ._commentLine(");");
2574                 this._codeIndentLevel(-1);
2575                 
2576                 this._codeIndents()._newLine("}");
2577                 this._codeIndentLevel(-1);
2578                 
2579                 this._codeIndents()._code(")");
2580             },
2581 
2582             "raw": function (ast) {
2583                 this._visitRaw(ast.stmt, true);
2584             },
2585 
2586             "bind": function (ast) {
2587                 var info = ast.info;
2588                 
2589                 var commentPrefix = "";
2590                 if (info.assignee == "return") {
2591                     commentPrefix = "return ";
2592                 } else if (info.argName != "") {
2593                     commentPrefix = "var " + info.argName + " = ";
2594                 }
2595                 
2596                 this._code(this._builderVar + ".Bind(")._comment(commentPrefix + this._binder + "(")._visitRaw(info.expression)._comment(");")._newLine(", function (" + info.argName + ") {");
2597                 this._codeIndentLevel(1);
2598 
2599                 if (info.assignee == "return") {
2600                     this._codeIndents()
2601                         ._newLine("return " + this._builderVar + ".Return(" + info.argName + ");");
2602                 } else {
2603                     if (info.assignee) {
2604                         this._bothIndents()
2605                             ._visitRaw(info.assignee)._bothLine(" = " + info.argName + ";");
2606                     }
2607 
2608                     this._visitWindStatements(ast.stmts);
2609                 }
2610                 this._codeIndentLevel(-1);
2611 
2612                 this._codeIndents()
2613                     ._code("})");
2614             },
2615 
2616             "if": function (ast) {
2617 
2618                 for (var i = 0; i < ast.conditionStmts.length; i++) {
2619                     var stmt = ast.conditionStmts[i];
2620                     
2621                     this._both("if (")._visitRaw(stmt.cond)._bothLine(") {");
2622                     this._bothIndentLevel(1);
2623 
2624                     this._visitWindStatements(stmt.stmts);
2625                     this._bothIndentLevel(-1);
2626 
2627                     if (i < ast.conditionStmts.length - 1 || ast.elseStmts) {
2628                         this._bothIndents()._both("} else ");
2629                     } else {
2630                         this._bothIndents()._code("} else ")._comment("}");
2631                     }
2632                 }
2633 
2634                 if (ast.elseStmts) {
2635                     this._bothLine("{");
2636                     this._bothIndentLevel(1);
2637                 } else {
2638                     this._newLine("{");
2639                     this._codeIndentLevel(1);
2640                 }
2641 
2642                 if (ast.elseStmts) {
2643                     this._visitWindStatements(ast.elseStmts);
2644                 } else {
2645                     this._codeIndents()
2646                         ._newLine("return " + this._builderVar + ".Normal();");
2647                 }
2648 
2649                 if (ast.elseStmts) {
2650                     this._bothIndentLevel(-1);
2651                 } else {
2652                     this._codeIndentLevel(-1);
2653                 }
2654 
2655                 if (ast.elseStmts) {
2656                     this._bothIndents()
2657                         ._both("}");
2658                 } else {
2659                     this._codeIndents()
2660                         ._code("}");
2661                 }
2662             },
2663 
2664             "switch": function (ast) {
2665                 this._both("switch (")._visitRaw(ast.item)._bothLine(") {");
2666                 this._bothIndentLevel(1);
2667 
2668                 for (var i = 0; i < ast.caseStmts.length; i++) {
2669                     var caseStmt = ast.caseStmts[i];
2670                     
2671                     if (caseStmt.item) {
2672                         this._bothIndents()
2673                             ._both("case ")._visitRaw(caseStmt.item)._bothLine(":");
2674                     } else {
2675                         this._bothIndents()._bothLine("default:");
2676                     }
2677                     this._bothIndentLevel(1);
2678 
2679                     this._visitWindStatements(caseStmt.stmts);                    
2680                     this._bothIndentLevel(-1);
2681                 }
2682 
2683                 this._bothIndents()._code("}");
2684             },
2685 
2686             "try": function (ast) {
2687                 this._codeLine(this._builderVar + ".Try(")._commentLine("try {");
2688                 this._bothIndentLevel(1);
2689 
2690                 this._bothIndents()._visitWind(ast.bodyStmt)._newLine(",");
2691                 this._commentIndentLevel(-1);
2692                 
2693                 if (ast.catchStmts) {
2694                     this._bothIndents()
2695                         ._codeLine("function (" + ast.exVar + ") {")
2696                         ._commentLine("} catch (" + ast.exVar + ") {");
2697                     this._bothIndentLevel(1);
2698 
2699                     this._visitWindStatements(ast.catchStmts);
2700                     this._bothIndentLevel(-1);
2701 
2702                     this._bothIndents()._codeLine("},");
2703                     if (ast.finallyStmt) {
2704                         this._commentLine("} finally {");
2705                     } else {
2706                         this._commentLine("}");
2707                     }
2708                 } else {
2709                     this._bothIndents()._codeLine("null,")._commentLine("} finally {");
2710                 }
2711                 
2712                 if (ast.finallyStmt) {
2713                     this._commentIndentLevel(1);
2714                     this._bothIndents()._visitWind(ast.finallyStmt)._newLine();
2715                     this._commentIndentLevel(-1);
2716                 } else {
2717                     this._codeIndents()._newLine("null");
2718                 }
2719                 this._codeIndentLevel(-1);
2720                 
2721                 this._codeIndents()._code(")");
2722                 if (ast.finallyStmt) {
2723                     this._commentIndents()._comment("}");
2724                 }
2725             },
2726 
2727             "normal": function (ast) {
2728                 this._code(this._builderVar + ".Normal()");
2729             },
2730 
2731             "throw": function (ast) {
2732                 this
2733                     ._code(this._builderVar + ".Throw(")
2734                     ._comment("throw ")
2735                         ._visitRaw(ast.stmt[1])
2736                             ._code(")")._comment(";");
2737             },
2738 
2739             "break": function (ast) {
2740                 this._code(this._builderVar + ".Break()")._comment("break;");
2741             },
2742 
2743             "continue": function (ast) {
2744                 this._code(this._builderVar + ".Continue()")._comment("continue;");
2745             },
2746 
2747             "return": function (ast) {
2748                 this._code(this._builderVar + ".Return(")._comment("return");
2749                 if (ast.stmt[1]) {
2750                     this._comment(" ")._visitRaw(ast.stmt[1]);
2751                 }
2752                 
2753                 this._code(")")._comment(";");
2754             }
2755         },
2756 
2757         _rawVisitors: {
2758             "var": function (ast) {
2759                 this._both("var ");
2760 
2761                 var items = ast[1];
2762                 for (var i = 0; i < items.length; i++) {
2763                     this._both(items[i][0]);
2764                     if (items[i].length > 1) {
2765                         this._both(" = ")._visitRaw(items[i][1]);
2766                     }
2767                     if (i < items.length - 1) this._both(", ");
2768                 }
2769 
2770                 this._both(";");
2771             },
2772 
2773             "seq": function (ast, noBracket) {
2774                 var left = ast[1];
2775                 var right = ast[2];
2776                 
2777                 if (!noBracket) this._both("(");
2778                 
2779                 this._visitRaw(left);
2780                 this._both(", ");
2781                 
2782                 if (right[0] == "seq") {
2783                     arguments.callee.call(this, right, true);
2784                 } else {
2785                     this._visitRaw(right);
2786                 }
2787                 
2788                 if (!noBracket) this._both(")");
2789             },
2790 
2791             "binary": function (ast) {
2792                 var op = ast[1], left = ast[2], right = ast[3];
2793 
2794                 if (getPrecedence(ast) < getPrecedence(left)) {
2795                     this._both("(")._visitRaw(left)._both(") ");
2796                 } else {
2797                     this._visitRaw(left)._both(" ");
2798                 }
2799 
2800                 this._both(op);
2801 
2802                 if (getPrecedence(ast) <= getPrecedence(right)) {
2803                     this._both(" (")._visitRaw(right)._both(")");
2804                 } else {
2805                     this._both(" ")._visitRaw(right);
2806                 }
2807             },
2808 
2809             "sub": function (ast) {
2810                 var prop = ast[1], index = ast[2];
2811 
2812                 if (getPrecedence(ast) < getPrecedence(prop)) {
2813                     this._both("(")._visitRaw(prop)._both(")[")._visitRaw(index)._both("]");
2814                 } else {
2815                     this._visitRaw(prop)._both("[")._visitRaw(index)._both("]");
2816                 }
2817             },
2818 
2819             "unary-postfix": function (ast) {
2820                 var op = ast[1];
2821                 var item = ast[2];
2822                 
2823                 if (getPrecedence(ast) <= getPrecedence(item)) {
2824                     this._both("(")._visitRaw(item)._both(")");
2825                 } else {
2826                     this._visitRaw(item);
2827                 }
2828                 
2829                 this._both(" " + op);
2830             },
2831 
2832             "unary-prefix": function (ast) {
2833                 var op = ast[1];
2834                 var item = ast[2];
2835                 
2836                 this._both(op + " ");
2837                 
2838                 if (getPrecedence(ast) < getPrecedence(item)) {
2839                     this._both("(")._visitRaw(item)._both(")");
2840                 } else {
2841                     this._visitRaw(item);
2842                 }
2843             },
2844 
2845             "assign": function (ast) {
2846                 var op = ast[1];
2847                 var name = ast[2];
2848                 var value = ast[3];
2849                 
2850                 if (name[0] == "assign") {
2851                     this._both("(")._visitRaw(name)._both(")");
2852                 } else {
2853                     this._visitRaw(name);
2854                 }
2855                 
2856                 if ((typeof op) == "string") {
2857                     this._both(" " + op + "= ");
2858                 } else {
2859                     this._both(" = ");
2860                 }
2861                 
2862                 this._visitRaw(value);
2863             },
2864 
2865             "stat": function (ast) {
2866                 this._visitRaw(ast[1])._both(";");
2867             },
2868 
2869             "dot": function (ast) {
2870                 var left = ast[1];
2871                 var right = ast[2];
2872                 
2873                 if (getPrecedence(ast) < getPrecedence(left)) {
2874                     this._both("(")._visitRaw(left)._both(").")._both(right);
2875                 } else {
2876                     this._visitRaw(left)._both(".")._both(right);
2877                 }
2878             },
2879 
2880             "new": function (ast) {
2881                 var ctor = ast[1];
2882 
2883                 this._both("new ")._visitRaw(ctor)._both("(");
2884 
2885                 var args = ast[2];
2886                 for (var i = 0, len = args.length; i < len; i++) {
2887                     this._visitRaw(args[i]);
2888                     if (i < len - 1) this._both(", ");
2889                 }
2890 
2891                 this._both(")");
2892             },
2893 
2894             "call": function (ast) {
2895             
2896                 if (isWindPattern(ast)) {
2897                     compileWindPattern(ast, this._seedProvider, this._codeWriter, this._commentWriter);
2898                 } else {
2899                     var caller = ast[1];
2900                 
2901                     var invalidBind = (caller[0] == "name") && (caller[1] == this._binder);
2902                     // throw?
2903 
2904                     if (getPrecedence(ast) < getPrecedence(caller)) {
2905                         this._both("(")._visitRaw(caller)._both(")");
2906                     } else {
2907                         this._visitRaw(caller);
2908                     }
2909                     
2910                     this._both("(");
2911 
2912                     var args = ast[2];
2913                     for (var i = 0; i < args.length; i++) {
2914                         this._visitRaw(args[i]);
2915                         if (i < args.length - 1) this._both(", ");
2916                     }
2917 
2918                     this._both(")");
2919                 }
2920             },
2921 
2922             "name": function (ast) {
2923                 this._both(ast[1]);
2924             },
2925 
2926             "object": function (ast) {
2927                 var items = ast[1];
2928                 if (items.length <= 0) {
2929                     this._both("{ }");
2930                 } else {
2931                     this._bothLine("{");
2932                     this._bothIndentLevel(1);
2933                     
2934                     for (var i = 0; i < items.length; i++) {
2935                         this._bothIndents()
2936                             ._both(stringify(items[i][0]) + ": ")
2937                             ._visitRaw(items[i][1]);
2938                         
2939                         if (i < items.length - 1) {
2940                             this._bothLine(",");
2941                         } else {
2942                             this._bothLine("");
2943                         }
2944                     }
2945                     
2946                     this._bothIndentLevel(-1);
2947                     this._bothIndents()._both("}");
2948                 }
2949             },
2950 
2951             "array": function (ast) {
2952                 this._both("[");
2953 
2954                 var items = ast[1];
2955                 for (var i = 0; i < items.length; i++) {
2956                     this._visitRaw(items[i]);
2957                     if (i < items.length - 1) this._both(", ");
2958                 }
2959 
2960                 this._both("]");
2961             },
2962 
2963             "num": function (ast) {
2964                 this._both(ast[1]);
2965             },
2966 
2967             "regexp": function (ast) {
2968                 this._both("/" + ast[1] + "/" + ast[2]);
2969             },
2970 
2971             "string": function (ast) {
2972                 this._both(stringify(ast[1]));
2973             },
2974 
2975             "function": function (ast) {
2976                 this._visitRawFunction(ast);
2977             },
2978 
2979             "defun": function (ast) {
2980                 this._visitRawFunction(ast);
2981             },
2982             
2983             "for": function (ast) {
2984                 this._both("for (");
2985 
2986                 var setup = ast[1];
2987                 if (setup) {
2988                     this._visitRaw(setup);
2989                     if (setup[0] != "var") {
2990                         this._both("; ");
2991                     } else {
2992                         this._both(" ");
2993                     }
2994                 } else {
2995                     this._both("; ");
2996                 }
2997 
2998                 var condition = ast[2];
2999                 if (condition) this._visitRaw(condition);
3000                 this._both("; ");
3001 
3002                 var update = ast[3];
3003                 if (update) this._visitRaw(update);
3004                 this._both(") ");
3005 
3006                 var currInLoop = this._pos.inLoop;
3007                 this._pos.inLoop = true;
3008 
3009                 var body = ast[4];
3010                 this._visitRawBody(body);
3011 
3012                 this._pos.inLoop = currInLoop;
3013             },
3014 
3015             "for-in": function (ast) {
3016                 this._both("for (");
3017 
3018                 var declare = ast[1];
3019                 if (declare[0] == "var") { // declare == ["var", [["m"]]]
3020                     this._both("var " + declare[1][0][0]);
3021                 } else {
3022                     this._visitRaw(declare);
3023                 }
3024                 
3025                 this._both(" in ")._visitRaw(ast[3])._both(") ");
3026 
3027                 var currInLoop = this._pos.inLoop;
3028                 this._pos.inLoop = true;
3029                 
3030                 var body = ast[4];
3031                 this._visitRawBody(body);
3032 
3033                 this._pos.inLoop = currInLoop;
3034             },
3035 
3036             "block": function (ast) {
3037                 if (ast.length > 1) {            
3038                     this._bothLine("{")
3039                     this._bothIndentLevel(1);
3040 
3041                     this._visitRawStatements(ast[1]);
3042                     this._bothIndentLevel(-1);
3043 
3044                     this._bothIndents()
3045                         ._both("}");
3046                 } else {
3047                     this._both(";");
3048                 }
3049             },
3050 
3051             "while": function (ast) {
3052                 var condition = ast[1];
3053                 var body = ast[2];
3054 
3055                 var currInLoop = this._pos.inLoop;
3056                 this._pos.inLoop = true;
3057 
3058                 this._both("while (")._visitRaw(condition)._both(") ")._visitRawBody(body);
3059 
3060                 this._pos.inLoop = currInLoop;
3061             },
3062 
3063             "do": function (ast) {
3064                 var condition = ast[1];
3065                 var body = ast[2];
3066 
3067                 var currInLoop = this._pos.inLoop;
3068                 this._pos.inLoop = true;
3069 
3070                 this._both("do ")._visitRawBody(body);
3071 
3072                 this._pos.inLoop = currInLoop;
3073 
3074                 if (body[0] == "block") {
3075                     this._both(" ");
3076                 } else {
3077                     this._bothLine()
3078                         ._bothIndents();
3079                 }
3080 
3081                 this._both("while (")._visitRaw(condition)._both(");");
3082             },
3083 
3084             "if": function (ast) {
3085                 var condition = ast[1];
3086                 var thenPart = ast[2];
3087 
3088                 this._both("if (")._visitRaw(condition)._both(") ")._visitRawBody(thenPart);
3089 
3090                 var elsePart = ast[3];
3091                 if (elsePart) {
3092                     if (thenPart[0] == "block") {
3093                         this._both(" ");
3094                     } else {
3095                         this._bothLine("")
3096                             ._bothIndents();
3097                     }
3098 
3099                     if (elsePart[0] == "if") {
3100                         this._both("else ")._visitRaw(elsePart);
3101                     } else {
3102                         this._both("else ")._visitRawBody(elsePart);
3103                     }
3104                 }
3105             },
3106 
3107             "break": function (ast) {
3108                 if (this._pos.inLoop || this._pos.inSwitch) {
3109                     this._both("break;");
3110                 } else {
3111                     this._code("return ")._visitWind({ type: "break", stmt: ast })._code(";");
3112                 }
3113             },
3114 
3115             "continue": function (ast) {
3116                 if (this._pos.inLoop) {
3117                     this._both("continue;");
3118                 } else {
3119                     this._code("return ")._visitWind({ type: "continue", stmt: ast })._code(";");
3120                 }
3121             },
3122 
3123             "return": function (ast) {
3124                 if (this._pos.inFunction) {
3125                     this._both("return");
3126                     var value = ast[1];
3127                     if (value) this._both(" ")._visitRaw(value);
3128                     this._both(";");
3129                 } else {
3130                     this._code("return ")._visitWind({ type: "return", stmt: ast })._code(";");
3131                 }
3132             },
3133 
3134             "throw": function (ast) {
3135                 var pos = this._pos;
3136                 if (pos.inTry || pos.inFunction) {
3137                     this._both("throw ")._visitRaw(ast[1])._both(";");
3138                 } else {
3139                     this._code("return ")._visitWind({ type: "throw", stmt: ast })._code(";");
3140                 }
3141             },
3142 
3143             "conditional": function (ast) {
3144                 this._both("(")._visitRaw(ast[1])._both(") ? (")._visitRaw(ast[2])._both(") : (")._visitRaw(ast[3])._both(")");
3145             },
3146 
3147             "try": function (ast) {
3148 
3149                 this._bothLine("try {");
3150                 this._bothIndentLevel(1);
3151 
3152                 var currInTry = this._pos.inTry;
3153                 this._pos.inTry = true;
3154 
3155                 this._visitRawStatements(ast[1]);
3156                 this._bothIndentLevel(-1);
3157 
3158                 this._pos.inTry = currInTry;
3159 
3160                 var catchClause = ast[2];
3161                 var finallyStatements = ast[3];
3162 
3163                 if (catchClause) {
3164                     this._bothIndents()
3165                         ._bothLine("} catch (" + catchClause[0] + ") {")
3166                     this._bothIndentLevel(1);
3167 
3168                     this._visitRawStatements(catchClause[1]);
3169                     this._bothIndentLevel(-1);
3170                 }
3171 
3172                 if (finallyStatements) {
3173                     this._bothIndents()
3174                         ._bothLine("} finally {");
3175                     this._bothIndentLevel(1);
3176 
3177                     this._visitRawStatements(finallyStatements);
3178                     this._bothIndentLevel(-1);
3179                 }                
3180 
3181                 this._bothIndents()
3182                     ._both("}");
3183             },
3184 
3185             "switch": function (ast) {
3186                 this._both("switch (")._visitRaw(ast[1])._bothLine(") {");
3187                 this._bothIndentLevel(1);
3188 
3189                 var currInSwitch = this._pos.inSwitch;
3190                 this._pos.inSwitch = true;
3191 
3192                 var cases = ast[2];
3193                 for (var i = 0; i < cases.length; i++) {
3194                     var c = cases[i];
3195                     this._bothIndents();
3196 
3197                     if (c[0]) {
3198                         this._both("case ")._visitRaw(c[0])._bothLine(":");
3199                     } else {
3200                         this._bothLine("default:");
3201                     }
3202                     this._bothIndentLevel(1);
3203 
3204                     this._visitRawStatements(c[1]);
3205                     this._bothIndentLevel(-1);
3206                 }
3207                 this._bothIndentLevel(-1);
3208 
3209                 this._pos.inSwitch = currInSwitch;
3210 
3211                 this._bothIndents()
3212                     ._both("}");
3213             }
3214         }
3215     };
3216     
3217     var merge = function (commentLines, codeLines) {
3218         var length = commentLines.length;
3219         
3220         var maxShift = 0;
3221         
3222         for (var i = 0; i < length; i++) {
3223             var matches = codeLines[i].match(" +");
3224             var spaceLength = matches ? matches[0].length : 0;
3225             
3226             var shift = commentLines[i].length - spaceLength + 10;
3227             if (shift > maxShift) {
3228                 maxShift = shift;
3229             }
3230         }
3231         
3232         var shiftBuffer = new Array(maxShift);
3233         for (var i = 0; i < maxShift; i++) {
3234             shiftBuffer[i] = " ";
3235         }
3236         
3237         var shiftSpaces = shiftBuffer.join("");
3238 
3239         var buffer = [];
3240         for (var i = 0; i < length; i++) {
3241             var comment = commentLines[i]; 
3242             if (comment.replace(/ +/g, "").length > 0) {
3243                 comment = "/* " + comment + " */   ";
3244             }
3245             
3246             var code = shiftSpaces + codeLines[i];
3247             
3248             buffer.push(comment);
3249             buffer.push(code.substring(comment.length));
3250             
3251             if (i != length - 1) {
3252                 buffer.push("\n");
3253             }
3254         }
3255         
3256         return buffer.join("");
3257     }
3258     
3259     var sourceUrlSeed = 0;
3260     
3261     var getOptions = function (options) {
3262         options = options || { };
3263         options.root = options.root || "Wind";
3264         options.noSourceUrl = options.noSourceUrl || false;
3265         
3266         return options;
3267     }
3268     
3269     var compile = function (builderName, func, options) {
3270         options = getOptions(options);
3271         
3272         var funcCode = func.toString();
3273         var evalCode = "eval(" + compile.rootName + ".compile(" + stringify(builderName) + ", " + funcCode + "))"
3274         var evalCodeAst = parse(evalCode);
3275 
3276         var codeWriter = new CodeWriter();
3277         var commentWriter = new CodeWriter();
3278         
3279         // [ "toplevel", [ [ "stat", [ "call", ... ] ] ] ]
3280         var evalAst = evalCodeAst[1][0][1];
3281         var funcName = compileWindPattern(evalAst, new SeedProvider(), codeWriter, commentWriter);
3282         
3283         var newCode = merge(commentWriter.lines, codeWriter.lines);
3284         if (!options.noSourceUrl) {
3285             newCode += ("\n//@ sourceURL=wind/" + (sourceUrlSeed++) + "_" + (funcName || "anonymous") + ".js");
3286         }
3287         
3288         Wind.logger.debug("// Original: \r\n" + funcCode + "\r\n\r\n// Compiled: \r\n" + newCode + "\r\n");
3289         
3290         return codeGenerator(newCode);
3291     }
3292 
3293     compile.rootName = "Wind";
3294 
3295     // CommonJS
3296     var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);
3297     // CommonJS AMD
3298     var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);
3299 
3300     var defineModule = function () {
3301         Wind.define({
3302             name: "compiler",
3303             version: "0.7.2",
3304             require: isCommonJS && require,
3305             dependencies: { core: "~0.7.0" },
3306             init: function () {
3307                 Wind.parse = parse;
3308                 Wind.compile = compile;
3309             }
3310         });
3311     }
3312 
3313     if (isCommonJS) {
3314         try {
3315             Wind = require("./wind-core");
3316         } catch (ex) {
3317             Wind = require("wind-core");
3318         }
3319         
3320         defineModule();
3321     } else if (isAmd) {
3322         require(["wind-core"], function (wind) {
3323             Wind = wind;
3324             defineModule();
3325         });
3326     } else {
3327         var Fn = Function, global = Fn(‘return this‘)();
3328         if (!global.Wind) {
3329             throw new Error(‘Missing the root object, please load "wind" component first.‘);
3330         }
3331         
3332         Wind = global.Wind;
3333         defineModule();
3334     }
3335 })();
3336 
3337 /***********************************************************************
3338   wind-builderbase-0.7.0.js
3339  ***********************************************************************/
3340 
3341 (function () {
3342     "use strict";
3343     
3344     var BuilderBase = function () { }
3345     BuilderBase.prototype = {
3346         For: function (condition, update, body) {
3347             return {
3348                 next: function (_this, callback) {
3349                     
3350                     var loop = function (skipUpdate) {
3351                         try {
3352                             if (update && !skipUpdate) {
3353                                 update.call(_this);
3354                             }
3355 
3356                             if (!condition || condition.call(_this)) {
3357                                 body.next(_this, function (type, value, target) {
3358                                     if (type == "normal" || type == "continue") {
3359                                         loop(false);
3360                                     } else if (type == "throw" || type == "return") {
3361                                         callback(type, value);
3362                                     } else if (type == "break") {
3363                                         callback("normal");
3364                                     } else {
3365                                         throw new Error(‘Invalid type for "Loop": ‘ + type);
3366                                     }
3367                                 });
3368                             } else {
3369                                 callback("normal");
3370                             }
3371                         } catch (ex) {
3372                             callback("throw", ex);
3373                         }
3374                     }
3375                     
3376                     loop(true);
3377                 }
3378             };
3379         },
3380         
3381         ForIn: function (obj, bodyGenerator) {
3382             return {
3383                 next: function (_this, callback) {
3384                 
3385                     var keys = [];
3386                     for (var k in obj) {
3387                         keys.push(k);
3388                     }
3389                     
3390                     var loop = function (i) {
3391                         try {
3392                             if (i < keys.length) {
3393                                 var body = bodyGenerator(keys[i]);
3394                                 body.next(_this, function (type, value, target) {
3395                                     if (type == "normal" || type == "continue") {
3396                                         loop(i + 1);
3397                                     } else if (type == "throw" || type == "return") {
3398                                         callback(type, value);
3399                                     } else if (type == "break") {
3400                                         callback("normal");
3401                                     } else {
3402                                         throw new Error(‘Invalid type for "Loop": ‘ + type);
3403                                     }
3404                                 });
3405                             } else {
3406                                 callback("normal");
3407                             }
3408                         } catch (ex) {
3409                             callback("throw", ex);
3410                         }
3411                     }
3412                     
3413                     loop(0);
3414                 }
3415             };
3416         },
3417         
3418         While: function (condition, body) {
3419             return {
3420                 next: function (_this, callback) {
3421                     var loop = function () {
3422                         try {
3423                             if (condition.call(_this)) {
3424                                 body.next(_this, function (type, value, target) {
3425                                     if (type == "normal" || type == "continue") {
3426                                         loop();
3427                                     } else if (type == "throw" || type == "return") {
3428                                         callback(type, value);
3429                                     } else if (type == "break") {
3430                                         callback("normal");
3431                                     } else {
3432                                         throw new Error(‘Invalid type for "Loop": ‘ + type);
3433                                     }
3434                                 });
3435                             } else {
3436                                 callback("normal");
3437                             }
3438                         } catch (ex) {
3439                             callback("throw", ex);
3440                         }
3441                     }
3442                     
3443                     loop();
3444                 }
3445             };
3446         },
3447         
3448         Do: function (body, condition) {
3449             return {
3450                 next: function (_this, callback) {
3451                 
3452                     var loop = function () {
3453                         body.next(_this, function (type, value, target) {
3454                             if (type == "normal" || type == "continue") {
3455                                 try {
3456                                     if (condition.call(_this)) {
3457                                         loop();
3458                                     } else {
3459                                         callback("normal");
3460                                     }
3461                                 } catch (ex) {
3462                                     callback("throw", ex);
3463                                 }
3464                             } else if (type == "throw" || type == "return") {
3465                                 callback(type, value);
3466                             } else if (type == "break") {
3467                                 callback("normal");
3468                             } else {
3469                                 throw new Error(‘Invalid type for "Loop": ‘ + type);
3470                             }
3471                         });
3472                     };
3473                 
3474                     loop();
3475                 }
3476             };
3477         },
3478         
3479         Delay: function (generator) {
3480             return {
3481                 next: function (_this, callback) {
3482                     try {
3483                         var step = generator.call(_this);
3484                         step.next(_this, callback);
3485                     } catch (ex) {
3486                         callback("throw", ex);
3487                     }
3488                 }
3489             };
3490         },
3491 
3492         Combine: function (s1, s2) {
3493             return {
3494                 next: function (_this, callback) {
3495                     s1.next(_this, function (type, value, target) {
3496                         if (type == "normal") {
3497                             try {
3498                                 s2.next(_this, callback);
3499                             } catch (ex) {
3500                                 callback("throw", ex);
3501                             }
3502                         } else {
3503                             callback(type, value, target);
3504                         }
3505                     });
3506                 }
3507             };
3508         },
3509 
3510         Return: function (result) {
3511             return {
3512                 next: function (_this, callback) {
3513                     callback("return", result);
3514                 }
3515             };
3516         },
3517 
3518         Normal: function () {
3519             return {
3520                 next: function (_this, callback) {
3521                     callback("normal");
3522                 }
3523             };
3524         },
3525 
3526         Break: function () {
3527             return {
3528                 next: function (_this, callback) {
3529                     callback("break");
3530                 }
3531             };
3532         },
3533 
3534         Continue: function () {
3535             return {
3536                 next: function (_this, callback) {
3537                     callback("continue");
3538                 }
3539             };
3540         },
3541 
3542         Throw: function (ex) {
3543             return {
3544                 next: function (_this, callback) {
3545                     callback("throw", ex);
3546                 }
3547             };
3548         },
3549 
3550         Try: function (tryTask, catchGenerator, finallyStep) {
3551             return {
3552                 next: function (_this, callback) {
3553                     tryTask.next(_this, function (type, value, target) {
3554                         if (type != "throw" || !catchGenerator) {
3555                             if (!finallyStep) {
3556                                 callback(type, value, target);
3557                             } else {
3558                                 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {
3559                                     if (finallyType == "normal") {
3560                                         callback(type, value, target);
3561                                     } else {
3562                                         callback(finallyType, finallyValue, finallyTarget);
3563                                     }
3564                                 });
3565                             }
3566                         } else {
3567 
3568                             if (catchGenerator) {
3569 
3570                                 var catchTask;
3571                                 try {
3572                                     catchTask = catchGenerator.call(_this, value);
3573                                 } catch (ex) {
3574                                     if (finallyStep) {
3575                                         finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {
3576                                             if (finallyType == "normal") {
3577                                                 callback("throw", ex);
3578                                             } else {
3579                                                 callback(finallyType, finallyValue, finallyTarget);
3580                                             }
3581                                         });
3582                                     } else {
3583                                         callback("throw", ex);
3584                                     }
3585                                 }
3586                                 
3587                                 if (catchTask) {
3588                                     catchTask.next(_this, function (catchType, catchValue, catchTarget) {
3589                                         if (catchType == "throw") {
3590                                             if (finallyStep) {
3591                                                 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {
3592                                                     if (finallyType == "normal") {
3593                                                         callback(catchType, catchValue, catchTarget);
3594                                                     } else {
3595                                                         callback(finallyType, finallyValue, finallyTarget);
3596                                                     }
3597                                                 });
3598                                             } else {
3599                                                 callback(catchType, catchValue, catchTarget);
3600                                             }
3601                                         } else {
3602                                             if (finallyStep) {
3603                                                 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {
3604                                                     if (finallyType == "normal") {
3605                                                         callback(catchType, catchValue, catchTarget);
3606                                                     } else {
3607                                                         callback(finallyType, finallyValue, finallyTarget);
3608                                                     }
3609                                                 });
3610                                             } else {
3611                                                 callback(catchType, catchValue, catchTarget);
3612                                             }
3613                                         }  
3614                                     });
3615                                 }
3616                             } else {
3617                                 finallyStep.next(_this, function (finallyType, finallyValue, finallyTarget) {
3618                                     if (finallyType == "normal") {
3619                                         callback(type, value, target);
3620                                     } else {
3621                                         callback(finallyType, finallyValue, finallyTarget);
3622                                     }
3623                                 });
3624                             }
3625                         }
3626                     });
3627                 }
3628             };
3629         }
3630     }
3631 
3632     // CommonJS
3633     var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);
3634     // CommonJS AMD
3635     var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);
3636 
3637     var Wind;
3638 
3639     var defineModule = function () {
3640         Wind.define({
3641             name: "builderbase",
3642             version: "0.7.0",
3643             require: isCommonJS && require,
3644             dependencies: { core: "~0.7.0" },
3645             init: function () {
3646                 Wind.BuilderBase = BuilderBase;
3647             }
3648         });
3649     }
3650 
3651     if (isCommonJS) {
3652         try {
3653             Wind = require("./wind-core");
3654         } catch (ex) {
3655             Wind = require("wind-core");
3656         }
3657         
3658         defineModule();
3659     } else if (isAmd) {
3660         require(["wind-core"], function (wind) {
3661             Wind = wind;
3662             defineModule();
3663         });
3664     } else {
3665         var Fn = Function, global = Fn(‘return this‘)();
3666         if (!global.Wind) {
3667             throw new Error(‘Missing the root object, please load "wind" component first.‘);
3668         }
3669         
3670         Wind = global.Wind;
3671         defineModule();
3672     }
3673 })();
3674 
3675 /***********************************************************************
3676   wind-async-0.7.1.js
3677  ***********************************************************************/
3678 
3679 (function () {
3680     "use strict";
3681 
3682     var supportDefineProperty = (function () {
3683         var i = 0;
3684         var getter = function () {
3685             if (i === 0) {
3686                 throw new Error("Execute too soon.");
3687             }
3688             
3689             return i;
3690         };
3691 
3692         var obj = {};
3693         
3694         try {
3695             Object.defineProperty(obj, "value", { get: getter });
3696             
3697             i = 1;
3698             return obj.value === 1;
3699         } catch (ex) {
3700             return false;
3701         }
3702     })();
3703     
3704     var Wind, _;
3705     
3706     var Async = { };
3707     
3708     /***********************************************************************
3709       Errors
3710      ***********************************************************************/
3711 
3712     var CanceledErrorTypeID = "670a1076-712b-4edd-9b70-64b152fe1cd9";
3713     var isCanceledError = function (ex) { return ex._typeId == CanceledErrorTypeID; }
3714     var CanceledError = Async.CanceledError = function () { }
3715     CanceledError.prototype = {
3716         isTypeOf: isCanceledError,
3717         _typeId: CanceledErrorTypeID,
3718         message: "The task has been cancelled."
3719     }
3720     
3721     var AggregateErrorTypeID = "4a73efb8-c2e2-4305-a05c-72385288650a";
3722     var AggregateError = Async.AggregateError = function (errors) {
3723         this.children = [];
3724         
3725         if (errors) {
3726             for (var i = 0; i < errors.length; i++) {
3727                 this.children.push(errors[i]);
3728             }
3729         }
3730     }
3731     AggregateError.prototype = {
3732         _typeId: AggregateErrorTypeID,
3733         message: "This is an error contains sub-errors, please check the ‘children‘ collection for more details.",
3734         isTypeOf: function (ex) {
3735             return ex._typeId == AggregateErrorTypeID;
3736         }
3737     }
3738 
3739     /***********************************************************************
3740       CancellationToken
3741      ***********************************************************************/
3742     
3743     var CancellationToken = Async.CancellationToken = function () { }
3744     CancellationToken.prototype = {
3745         register: function (handler) {
3746             if (this.isCancellationRequested) {
3747                 handler();
3748             }
3749 
3750             if (!this._handlers) {
3751                 this._handlers = [];
3752             }
3753 
3754             this._handlers.push(handler);
3755         },
3756         
3757         unregister: function (handler) {
3758             if (!this._handlers) {
3759                 return;
3760             }
3761             
3762             var index = this._handlers.indexOf(handler);
3763             if (index >= 0) {
3764                 this._handlers.splice(index, 1);
3765             }
3766         },
3767         
3768         cancel: function () {
3769             if (this.isCancellationRequested) {
3770                 return;
3771             }
3772 
3773             this.isCancellationRequested = true;
3774 
3775             var handlers = this._handlers;
3776             delete this._handlers;
3777 
3778             for (var i = 0; i < handlers.length; i++) {
3779                 try {
3780                     handlers[i]();
3781                 } catch (ex) {
3782                     Wind.logger.warn("Cancellation handler threw an error: " + ex);
3783                 }
3784             }
3785         },
3786 
3787         throwIfCancellationRequested: function () {
3788             if (this.isCancellationRequested) {
3789                 throw new CanceledError();
3790             }
3791         }
3792     };
3793 
3794     /***********************************************************************
3795       Task
3796      ***********************************************************************/
3797     
3798     var EventManager = function () {
3799         this._listeners = {};
3800         this._firing = null;
3801     }
3802     EventManager.prototype = {
3803         add: function (name, listener) {
3804             if (this._firing === name) {
3805                 var self = this;
3806                 setTimeout(function () {
3807                     self.add(name, listener);
3808                 }, 0);
3809                 
3810                 return;
3811             }
3812         
3813             var eventListeners = this._listeners[name];
3814             if (!eventListeners) {
3815                 eventListeners = this._listeners[name] = [];
3816             }
3817 
3818             eventListeners.push(listener);
3819         },
3820         
3821         remove: function (name, listener) {
3822             if (this._firing === name) {
3823                 var self = this;
3824                 setTimeout(function () {
3825                     self.remove(name, listener);
3826                 }, 0);
3827                 
3828                 return;
3829             }
3830         
3831             var eventListeners = this._listeners[name];
3832             if (!eventListeners) return;
3833             
3834             var index = eventListeners.indexOf(listener);
3835             if (index >= 0) {
3836                 eventListeners.splice(index, 1);
3837             }
3838         },
3839         
3840         fire: function (name, self, args) {
3841             var listeners = this._listeners[name];
3842             if (!listeners) return;
3843             
3844             this._firing = name;
3845 
3846             for (var i = 0; i < listeners.length; i++) {
3847                 try {
3848                     listeners[i].call(self, args);
3849                 } catch (ex) {
3850                     Wind.logger.warn(‘An error occurred in "‘ + name + ‘ listener": ‘ + ex);
3851                 }
3852             }
3853             
3854             this._firing = null;
3855         }
3856     };
3857     
3858     var taskEventManager = new EventManager();
3859     
3860     var Task = Async.Task = function (delegate) {
3861         this._delegate = delegate;
3862         this._eventManager = new EventManager();
3863         this.status = "ready";
3864     }
3865     Task.prototype = {
3866         start: function () {
3867             if (this.status != "ready") {
3868                 throw new Error(‘Task can only be started in "ready" status.‘);
3869             }
3870 
3871             this.status = "running";
3872             
3873             try {
3874                 this._delegate(this);
3875             } catch (ex) {
3876                 if (this.status == "running") {
3877                     this.complete("failure", ex);
3878                 } else {
3879                     Wind.logger.warn("An unexpected error occurred after the task is completed: " + ex);
3880                 }
3881             }
3882             
3883             return this;
3884         },
3885         
3886         complete: function (type, value) {
3887             if (type !== "success" && type !== "failure") {
3888                 throw new Error("Unsupported type: " + type);
3889             }
3890             
3891             if (this.status != "running") {
3892                 throw new Error(‘The "complete" method can only be called in "running" status.‘);
3893             }
3894 
3895             var eventManager = this._eventManager;
3896             this._eventManager = null;
3897             
3898             if (type === "success") {
3899                 this.status = "succeeded";
3900                 
3901                 if (supportDefineProperty) {
3902                     this._result = value;
3903                 } else {
3904                     this.result = value;
3905                 }
3906 
3907                 eventManager.fire("success", this);
3908             } else {
3909                 if (isCanceledError(value)) {
3910                     this.status = "canceled";
3911                 } else {
3912                     this.status = "faulted";
3913                 }
3914                 
3915                 if (supportDefineProperty) {
3916                     this._error = value;
3917                 } else {
3918                     this.error = value;
3919                 }
3920                 
3921                 eventManager.fire("failure", this);
3922             }
3923             
3924             eventManager.fire("complete", this);
3925             
3926             if (type !== "failure") return;
3927             if (!supportDefineProperty) return;
3928             if (this._errorObserved) return;
3929             
3930             var self = this;
3931             this._unobservedTimeoutToken = setTimeout(function () {
3932                 self._handleUnobservedError(value);
3933             }, Task.unobservedTimeout);
3934         },
3935         
3936         observeError: function () {
3937             if (this.status === "ready" || this.status === "running") {
3938                 throw new Error("The method could only be called when it‘s completed.");
3939             }
3940         
3941             if (!supportDefineProperty) return this.error;
3942         
3943             var token = this._unobservedTimeoutToken;
3944             if (token) {
3945                 clearTimeout(token);
3946                 this._unobservedTimeoutToken = null;
3947             }
3948             
3949             this._errorObserved = true;
3950             return this._error;
3951         },
3952         
3953         _handleUnobservedError: function (error) {
3954             this._unobservedTimeoutToken = null;
3955 
3956             var args = {
3957                 task: this,
3958                 error: error,
3959                 observed: false
3960             };
3961             
3962             taskEventManager.fire("unobservedError", Task, args);
3963             
3964             if (!args.observed) {
3965                 throw error;
3966             }
3967         },
3968         
3969         then: function (nextGenerator) {
3970             var firstTask = this;
3971             
3972             return Task.create(function (t) {
3973                 
3974                 var nextOnComplete = function () {
3975                     if (this.error) {
3976                         t.complete("failure", this.error);
3977                     } else {
3978                         t.complete("success", this.result);
3979                     }
3980                 };
3981                 
3982                 var processNext = function (nextTask) {
3983                     if (nextTask.status == "ready") {
3984                         nextTask.start();
3985                     }
3986                 
3987                     if (nextTask.status == "running") {
3988                         nextTask.on("complete", nextOnComplete);
3989                     } else {
3990                         nextOnComplete.call(nextTask);
3991                     }
3992                 };
3993                 
3994                 var firstOnComplete = function () {
3995                     if (this.error) {
3996                         return t.complete("failure", this.error);
3997                     }
3998                     
3999                     var nextTask;
4000                     try {
4001                         nextTask = nextGenerator(this.result);
4002                     } catch (ex) {
4003                         return t.complete("failure", ex);
4004                     }
4005                     
4006                     processNext(nextTask);
4007                 };
4008                 
4009                 if (firstTask.status == "ready") {
4010                     firstTask.start();
4011                 }
4012                 
4013                 if (firstTask.status == "running") {
4014                     firstTask.on("complete", firstOnComplete);
4015                 } else {
4016                     firstOnComplete.call(firstTask);
4017                 }
4018             });
4019         }
4020     };
4021     
4022     Task.prototype.on = Task.prototype.addEventListener = function () {
4023         var eventManager = this._eventManager;
4024         if (!eventManager) {
4025             throw new Error("Cannot add event listeners when the task is complete.");
4026         }
4027         
4028         eventManager.add.apply(eventManager, arguments);
4029         return this;
4030     };
4031     
4032     Task.prototype.off = Task.prototype.removeEventListener = function () {
4033         var eventManager = this._eventManager;
4034         if (!eventManager) {
4035             throw new Error("All the event listeners have been removed when the task was complete.");
4036         }
4037         
4038         eventManager.remove.apply(eventManager, arguments);
4039         return this;
4040     };
4041     
4042     if (supportDefineProperty) {
4043         Object.defineProperty(Task.prototype, "error", {
4044             get: function () {
4045                 return this.observeError();
4046             }
4047         });
4048         
4049         Object.defineProperty(Task.prototype, "result", {
4050             get: function () {
4051                 var error = this.observeError();
4052                 if (error) throw error;
4053                 
4054                 return this._result;
4055             }
4056         });
4057     }
4058     
4059     var observeErrorListener = function () { this.observeError(); };
4060     
4061     Task.on = Task.addEventListener = function () {
4062         taskEventManager.add.apply(taskEventManager, arguments);
4063     }
4064     
4065     Task.off = Task.removeEventListener = function (name, listener) {
4066         taskEventManager.remove.apply(taskEventManager, arguments);
4067     }
4068     
4069     Task.unobservedTimeout = 10 * 1000;
4070     
4071     var isTask = Task.isTask = function (t) {
4072         return t && (typeof t.start === "function") && (typeof t.addEventListener) === "function" && (typeof t.removeEventListener) === "function" && (typeof t.complete) === "function";
4073     };
4074     
4075     var create = Task.create = function (delegate) {
4076         return new Task(delegate);
4077     }
4078     
4079     /***********************************************************************
4080       Task helpers
4081      ***********************************************************************/
4082     
4083     var whenAll = Task.whenAll = function () {
4084         var inputTasks;
4085 
4086         if (arguments.length == 1) {
4087             var arg = arguments[0];
4088             if (isTask(arg)) { // a single task
4089                 inputTasks = [arg];
4090             } else {
4091                 inputTasks = arg;
4092             }
4093         } else {
4094             inputTasks = new Array(arguments.length);
4095             for (var i = 0; i < arguments.length; i++) {
4096                 inputTasks[i] = arguments[i];
4097             }
4098         }
4099     
4100         return create(function (taskWhenAll) {
4101 
4102             var errors;
4103             
4104             var done = function () {
4105                 if (errors) {
4106                     taskWhenAll.complete("failure", new AggregateError(errors));
4107                 } else {
4108                     var results = _.map(inputTasks, function (t) {
4109                         return t.result;
4110                     });
4111                     
4112                     taskWhenAll.complete("success", results);
4113                 }
4114             }
4115 
4116             var runningNumber = 0;
4117 
4118             _.each(inputTasks, function (key, task) {
4119                 if (!task) return;
4120                 
4121                 if (!isTask(task)) {
4122                     inputTasks[key] = task = whenAll(task);
4123                 }
4124                 
4125                 if (task.status === "ready") {
4126                     task.start();
4127                 }
4128                 
4129                 if (task.status === "running") {
4130                     runningNumber++;
4131                     task.addEventListener("complete", function () {
4132                         if (this.status !== "succeeded") {
4133                             if (!errors) errors = [];
4134                             errors.push(this.error);
4135                         }
4136 
4137                         if (--runningNumber == 0) {
4138                             done();
4139                         }
4140                     });
4141                 } else if (task.status === "faulted" || task.status === "canceled") {
4142                     if (!errors) errors = [];
4143                     errors.push(task.error);
4144                 }
4145             });
4146 
4147             if (runningNumber == 0) {
4148                 done();
4149             }
4150         });
4151     };
4152     
4153     var whenAny = Task.whenAny = function () {
4154 
4155         var inputTasks = { };
4156         var isArray = true;
4157 
4158         if (arguments.length == 1) {
4159             var arg = arguments[0];
4160             if (isTask(arg)) {
4161                 inputTasks[0] = arg;
4162             } else {
4163                 isArray = _.isArray(arg);
4164                 _.each(arg, function (key, task) {
4165                     if (isTask(task)) {
4166                         inputTasks[key] = task;
4167                     }
4168                 });
4169             }
4170         } else {
4171             for (var i = 0; i < arguments.length; i++) {
4172                 var task = arguments[i];
4173                 if (isTask(task)) {
4174                     inputTasks[i] = task;
4175                 }
4176             }
4177         }
4178         
4179         var processKey = isArray
4180             ? function (key) { return parseInt(key, 10); }
4181             : function (key) { return key; }
4182         
4183         return create(function (taskWhenAny) {
4184             if (_.isEmpty(inputTasks)) {
4185                 return taskWhenAny.complete("failure", "There‘s no valid input tasks.");
4186             }
4187             
4188             var result;
4189             
4190             _.each(inputTasks, function (key, task) {
4191                 if (task.status === "ready") {
4192                     task.start();
4193                 }
4194                 
4195                 if (task.status !== "running") {
4196                     task.observeError();
4197                     
4198                     if (!result) {
4199                         result = { key: processKey(key), task: task };
4200                     }
4201                 }
4202             });
4203             
4204             if (result) {
4205                 _.each(inputTasks, function (key, task) {
4206                     if (task.status === "running") {
4207                         task.on("failure", observeErrorListener);
4208                     }
4209                 });
4210 
4211                 return taskWhenAny.complete("success", result);
4212             }
4213             
4214             var onComplete = function () {
4215                 this.observeError();
4216                 
4217                 var taskCompleted = this;
4218                 var keyCompleted;
4219                 
4220                 _.each(inputTasks, function (key, task) {
4221                     if (taskCompleted === task) {
4222                         keyCompleted = key;
4223                         return;
4224                     }
4225 
4226                     task.off("complete", onComplete);
4227                     task.on("failure", observeErrorListener);
4228                 });
4229 
4230                 taskWhenAny.complete("success", { key: processKey(keyCompleted), task: this });
4231             }
4232             
4233             _.each(inputTasks, function (task) {
4234                 task.addEventListener("complete", onComplete);
4235             });
4236         });
4237     }
4238 
4239     /***********************************************************************
4240       Async helpers
4241      ***********************************************************************/
4242     
4243     var sleep = Async.sleep = function (delay, /* CancellationToken */ ct) {
4244         return Task.create(function (t) {
4245             if (ct && ct.isCancellationRequested) {
4246                 t.complete("failure", new CanceledError());
4247             }
4248 
4249             var seed;
4250             var cancelHandler;
4251             
4252             if (ct) {
4253                 cancelHandler = function () {
4254                     clearTimeout(seed);
4255                     t.complete("failure", new CanceledError());
4256                 }
4257             }
4258             
4259             var seed = setTimeout(function () {
4260                 if (ct) {
4261                     ct.unregister(cancelHandler);
4262                 }
4263                 
4264                 t.complete("success");
4265             }, delay);
4266             
4267             if (ct) {
4268                 ct.register(cancelHandler);
4269             }
4270         });
4271     }
4272     
4273     var onEvent = Async.onEvent = function (target, eventName, /* CancellationToken*/ ct) {
4274         return Task.create(function (t) {
4275             if (ct && ct.isCancellationRequested) {
4276                 t.complete("failure", new CanceledError());
4277             }
4278 
4279             var cleanUp = function () {
4280                 if (target.removeEventListener) {
4281                     target.removeEventListener(eventName, eventHandler);
4282                 } else if (target.removeListener) {
4283                     target.removeListener(eventName, eventHandler);
4284                 } else {
4285                     target.detachEvent(eventName, eventHandler);
4286                 }
4287             }
4288             
4289             var eventHandler;
4290             var cancelHandler;
4291 
4292             if (ct) {
4293                 cancelHandler = function () {
4294                     cleanUp();
4295                     t.complete("failure", new CanceledError());
4296                 }
4297             }
4298             
4299             var eventHandler = function (ev) {
4300                 if (ct) {
4301                     ct.unregister(cancelHandler);
4302                 }
4303                 
4304                 cleanUp();
4305                 t.complete("success", ev);
4306             }
4307             
4308             if (target.addEventListener) {
4309                 target.addEventListener(eventName, eventHandler);
4310             } else if (target.addListener) {
4311                 target.addListener(eventName, eventHandler);
4312             } else {
4313                 target.attachEvent(eventName, eventHandler);
4314             }
4315             
4316             if (ct) {
4317                 ct.register(cancelHandler);
4318             }
4319         });
4320     }
4321     
4322     /***********************************************************************
4323       AsyncBuilder
4324      ***********************************************************************/
4325     
4326     var AsyncBuilder = Async.AsyncBuilder = function () { }
4327     AsyncBuilder.prototype = {
4328         Start: function (_this, task) {
4329             return Task.create(function (t) {
4330                 task.next(_this, function (type, value, target) {
4331                     if (type == "normal" || type == "return") {
4332                         t.complete("success", value);
4333                     } else if (type == "throw") {
4334                         t.complete("failure", value);
4335                     } else {
4336                         throw new Error("Unsupported type: " + type);
4337                     }
4338                 });
4339             });
4340         },
4341 
4342         Bind: function (task, generator) {
4343             return {
4344                 next: function (_this, callback) {
4345                     
4346                     var onComplete = function () {
4347                         if (this.error) {
4348                             callback("throw", this.error);
4349                         } else {
4350                             var nextTask;
4351                             try {
4352                                 nextTask = generator.call(_this, this.result);
4353                             } catch (ex) {
4354                                 callback("throw", ex);
4355                                 return;
4356                             }
4357 
4358                             nextTask.next(_this, callback);
4359                         }
4360                     }
4361 
4362                     if (task.status == "ready") {
4363                         task.addEventListener("complete", onComplete);
4364                         task.start();
4365                     } else if (task.status == "running") {
4366                         task.addEventListener("complete", onComplete);
4367                     } else {
4368                         onComplete.call(task);
4369                     }
4370                 }
4371             };
4372         }
4373     }
4374     
4375     var Binding = Async.Binding = { };
4376     
4377     var collectArgs = function (args, requiredArgs) {
4378         var result = [];
4379         for (var i = 0; i < args.length; i++) {
4380             result.push(args[i]);
4381         }
4382 
4383         while (result.length < requiredArgs) {
4384             result.push(undefined);
4385         }
4386 
4387         return result;
4388     }
4389     
4390     var collectCallbackArgNames = function (args) {
4391         if (args.length <= 1) return null;
4392         
4393         var result = [];
4394         for (var i = 1; i < args.length; i++) {
4395             result.push(args[i]);
4396         }
4397         
4398         return result;
4399     }
4400     
4401     var fromStandard = Binding.fromStandard = function (fn) {
4402         var callbackArgNames = collectCallbackArgNames(arguments);
4403     
4404         return function () {
4405             var _this = this;
4406             var args = collectArgs(arguments, fn.length - 1);
4407 
4408             return Task.create(function (t) {
4409                 args.push(function (error, result) {
4410                     if (error) {
4411                         t.complete("failure", error);
4412                     } else if (!callbackArgNames) {
4413                         t.complete("success", result);
4414                     } else {
4415                         var data = {};
4416                         for (var i = 0; i < callbackArgNames.length; i++) {
4417                             data[callbackArgNames[i]] = arguments[i + 1];
4418                         }
4419                         
4420                         return t.complete("success", data);
4421                     }
4422                 });
4423                 
4424                 fn.apply(_this, args);
4425             });
4426         };
4427     };
4428     
4429     var fromCallback = Binding.fromCallback = function (fn) {
4430         var callbackArgNames = collectCallbackArgNames(arguments);
4431     
4432         return function () {
4433             var _this = this;
4434             var args = collectArgs(arguments, fn.length - 1);
4435 
4436             return Task.create(function (t) {
4437                 args.push(function (result) {
4438                     if (callbackArgNames) {
4439                         var data = {};
4440                         for (var i = 0; i < callbackArgNames.length; i++) {
4441                             data[callbackArgNames[i]] = arguments[i];
4442                         }
4443                         
4444                         t.complete("success", data);
4445                     } else {
4446                         t.complete("success", result);
4447                     }
4448                 });
4449                 
4450                 fn.apply(_this, args);
4451             });
4452         };
4453     };
4454     
4455     // CommonJS
4456     var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);
4457     // CommonJS AMD
4458     var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);
4459 
4460     var defineModule = function () {
4461         Wind.define({
4462             name: "async",
4463             version: "0.7.1",
4464             require: isCommonJS && require,
4465             autoloads: [ "builderbase" ],
4466             dependencies: { builderbase: "~0.7.0" },
4467             init: function () {
4468                 
4469                 _ = Wind._;
4470                 
4471                 _.each(Wind.BuilderBase.prototype, function (m, fn) {
4472                     AsyncBuilder.prototype[m] = fn;
4473                 });
4474                 
4475                 Wind.Async = Async;
4476             
4477                 Wind.binders["async"] = "$await";
4478                 Wind.builders["async"] = new AsyncBuilder();
4479             }
4480         });
4481     }
4482 
4483     if (isCommonJS) {
4484         try {
4485             Wind = require("./wind-core");
4486         } catch (ex) {
4487             Wind = require("wind-core");
4488         }
4489         
4490         defineModule();
4491     } else if (isAmd) {
4492         require(["wind-core"], function (wind) {
4493             Wind = wind;
4494             defineModule();
4495         });
4496     } else {
4497         var Fn = Function, global = Fn(‘return this‘)();
4498     
4499         if (!global.Wind) {
4500             throw new Error(‘Missing the root object, please load "wind" component first.‘);
4501         }
4502         
4503         Wind = global.Wind;
4504         defineModule();
4505     }
4506 })();
4507 
4508 
4509 /***********************************************************************
4510   wind-promise-0.7.0.js
4511  ***********************************************************************/
4512 
4513 (function () {
4514     "use strict";
4515 
4516     var Wind;
4517     
4518     var defaultCreate = function () {
4519         throw new Error(‘Please set "Wind.Promise.create" to provide a factory method for creating a promise object.‘);
4520     }
4521     
4522     var PromiseBuilder = function () { }
4523     PromiseBuilder.prototype = {
4524         Start: function (_this, task) {
4525             return Wind.Promise.create(function (complete, error) {
4526                 task.next(_this, function (type, value, target) {
4527                     if (type == "normal" || type == "return") {
4528                         complete(value);
4529                     } else if (type == "throw") {
4530                         error(value);
4531                     } else {
4532                         throw new Error("Unsupported type: " + type);
4533                     }
4534                 });
4535             });
4536         },
4537 
4538         Bind: function (promise, generator) {
4539             return {
4540                 next: function (_this, callback) {
4541                     promise.then(function (result) {
4542                         var nextTask;
4543                         try {
4544                             nextTask = generator.call(_this, result);
4545                         } catch (ex) {
4546                             return callback("throw", ex);
4547                         }
4548 
4549                         nextTask.next(_this, callback);
4550                     }, function (error) {
4551                         callback("throw", error);
4552                     });
4553                 }
4554             };
4555         }
4556     }
4557     
4558     // CommonJS
4559     var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);
4560     // CommonJS AMD
4561     var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);
4562 
4563     var defineModule = function () {
4564         Wind.define({
4565             name: "promise",
4566             version: "0.7.0",
4567             require: isCommonJS && require,
4568             autoloads: [ "builderbase" ],
4569             dependencies: { builderbase: "~0.7.0" },
4570             init: function () {
4571                 Wind._.each(Wind.BuilderBase.prototype, function (m, fn) {
4572                     PromiseBuilder.prototype[m] = fn;
4573                 });
4574             
4575                 if (!Wind.Promise) {
4576                     Wind.Promise = {};
4577                 }
4578                 
4579                 Wind.Promise.create = defaultCreate;
4580             
4581                 Wind.binders["promise"] = "$await";
4582                 Wind.builders["promise"] = new PromiseBuilder();
4583             }
4584         });
4585     }
4586 
4587     if (isCommonJS) {
4588         try {
4589             Wind = require("./wind-core");
4590         } catch (ex) {
4591             Wind = require("wind-core");
4592         }
4593         
4594         defineModule();
4595     } else if (isAmd) {
4596         require(["wind-core"], function (wind) {
4597             Wind = wind;
4598             defineModule();
4599         });
4600     } else {
4601         var Fn = Function, global = Fn(‘return this‘)();
4602 
4603         if (!global.Wind) {
4604             throw new Error(‘Missing the root object, please load "wind" component first.‘);
4605         }
4606         
4607         Wind = global.Wind;
4608         defineModule();
4609     }
4610 })();
wind-all-0.7.3.js

 

  

用Windjs画圆

标签:

原文地址:http://www.cnblogs.com/bigbigsunrise/p/4219026.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!