用Windjs画圆

  无意中接触了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>

  这里为了写的规范点,用了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>

  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                                  <[email protected]>
 344                                http://mihai.bazon.net/blog
 345
 346           Distributed under the BSD license:
 347
 348             Copyright 2010 (c) Mihai Bazon <[email protected]>
 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

  

时间: 2024-11-08 21:59:31

用Windjs画圆的相关文章

简单谈谈自己对htm与css中画圆的理解。

近几天,在利用css编辑中,发现不少边框图像要求是矩形圆角或者直接画一个圆的例子,下面和大家一起分享下对画圆的看法. 在这次的分享中,我侧重给大家看一些例子来更好的理解, 我们都明白,画圆时要用到“border-radius:”,而且在每次画圆时,我们都应该先设定一个width和height. 那么我们可以这样理解, 我们的圆是在一个矩形(正方形)中进行裁剪的,而border-radius就是我们要裁剪的尺寸. 给大家一些图片,更好的去理解. 首先,我们设定一个width为100px,高度为10

圆角背景实现,如实现圆角按钮;用xml文件画圆

项目中为了更好的视觉效果,然后又懒的去弄图片做背景时,往往就会通过xml布局文件来实现圆角的效果. 在drawable目录下新建一个shape类型的xml文件,设置<corners android:radius="5dp" />,然后在需要设为圆角的控件中,如按钮或LinearLayout,设置他们的background为drawable="@drawable/...".即可达到圆角的效果 // 用xml文件画圆 用竖线连接ListView的各个item

汇编画圆

汇编画圆-->效果如下图 代码如下: 1 dseg segment 2 center_x dw 150 ;原点坐标_x 3 center_y dw 90 ;原点坐标_y 4 radius dw 50 ;半径_r 5 label_x dw ? ;外接正方形右边界 6 label_y dw ? ;外接正方形下边界 7 distance dw ? 8 dseg ends 9 cseg segment 10 assume cs:cseg , ds:dseg 11 start: 12 mov ax , d

中点画线法画圆

中点画线法已经在画直线的时候详细讲过了,画圆时我们也可以用这种方法.画一个圆心为坐标原点的1/4圆,然后对其进行简单几何变换,平移对称,就可以得到任意圆. 类似的用中点画线法,从(0,r)点开始,每次要么向右走,要么向右下走,直到x==y,即到达四分之一圆处: (1)当d<0时,中点在圆内,则取正右方的点,(x+1,y+0.5),此时d=d+2*x+3; (2) 当d>=0时,中点在圆外,则取右下方的点,(x+1,y-1),此时d=d+2*(x-y)+5; (3) d0=1-r,即点(0,r)

h5画圆

下面一段代码是,h5的画圆,半圆,四分之一圆等效果 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> div{ width: 300px; height: 300px; border: 1px solid red; border-radius: 150

Unity GL 画圆

Unity下GL没有画圆的函数,只能自己来了. 如果能帮到大家,我也很高兴. 虽然没有画圆的函数,但是能画直线,利用这一点,配合微积分什么的,就可以画出来了.反正就是花很多连在一起的直线,每条直线足够短的时候,就足够圆了 1 void DrawCircle(float x, float y, float z, float r, float accuracy) 2 { 3 GL.PushMatrix (); 4 //绘制2D图像 5 GL.LoadOrtho (); 6 7 float strid

疯狂java 讲义第三章练习题---画圆

public class PaintRound{ /** * @author Dream_e. * @version v1.0 */ private int r;//圆的半径 PaintRound(int r){ this.r = r; } public void paint(){ int y = 2*r;//y的最大值为半径的2倍 int x = 0; int c = 0; int z = 2;//坐标轴递减量. for(int j = y; j >= 0; j-=z){ x = getX(r

ArcGIS JS 学习笔记2 实现仿百度的拖拽画圆

一.前言 吐槽一下,百度在国内除了百度地图是良心产品外,其他的真的不敢恭维.在上一篇笔记里,我已经实现了自定义的地图测量模块.在百度地图里面(其他地图)都有一个周边搜索的功能,拖拽画一个圆,然后以圆半径进行搜索(也就是缓冲区╮(╯_╰)╭). 这次的目标,就是要山寨这个拖拽画圆的功能,我先放一个效果图. 二.开始山寨 我们先想一想要实现这个功能需要哪些步骤. 拖拽 画圆 通知拖拽结束 2.1 实现拖拽 关于拖拽,有graphicslayer的拖拽事件和map的拖拽事件,如何选择呢?先来看一看官方

OpenGL画圆

中点画圆 1 #include<gl/glut.h> 2 3 4 void MidPointCirle(int r) 5 { 6 int x,y; 7 float d; 8 x=0;y=r;d=1.25-r; 9 glColor3f(1.0f,1.0f,1.0f); 10 glVertex2i(x,y); 11 while(x<=y) 12 { 13 if(d<0) 14 d+=2*x+3; 15 else 16 { 17 d+=2*(x-y)+5; 18 y--; 19 } 20