You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2018/07/05 10:03:55 UTC

[incubator-echarts-website] branch asf-site updated: sync en website and add online builder.

This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/incubator-echarts-website.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new d8ec7cb  sync en website and add online builder.
d8ec7cb is described below

commit d8ec7cbd9c7903a0bad30e15ffb774df98901669
Author: sushuang <su...@gmail.com>
AuthorDate: Thu Jul 5 18:03:03 2018 +0800

    sync en website and add online builder.
---
 README.md                                          |     4 +-
 _common.html                                       |     1 +
 _var.html                                          |     0
 _variablesLang.html                                |     0
 api.html                                           |    29 +-
 builder.html                                       |    80 +
 builder/build.js                                   |   272 +
 builder/chunk/amd.js                               |   127 +
 builder/chunk/end-3.js                             |    19 +
 builder/chunk/end.js                               |    35 +
 builder/chunk/start-3.js                           |    14 +
 builder/chunk/start.js                             |     1 +
 builder/echarts.html                               |    70 +
 builder/lib/FileSaver.js                           |   248 +
 builder/lib/escodegen.js                           |  2965 ++++++
 builder/lib/esl.js                                 |  1643 +++
 builder/lib/esprima.js                             |  5739 ++++++++++
 builder/lib/estraverse.js                          |   853 ++
 builder/lib/etpl.js                                |  1658 +++
 builder/lib/rollup.browser.js                      | 10626 +++++++++++++++++++
 builder/lib/uglify.js                              |     5 +
 builder/mangleString.js                            |   166 +
 builder/pre/removeDEV.js                           |    32 +
 builder/replaceDefine.js                           |    50 +
 builder/src/echarts/CoordinateSystem.js            |    54 +
 builder/src/echarts/ExtensionAPI.js                |    28 +
 .../src/echarts/action/createDataSelectAction.js   |    54 +
 builder/src/echarts/action/geoRoam.js              |    60 +
 builder/src/echarts/action/roamHelper.js           |    64 +
 builder/src/echarts/chart/bar.js                   |    36 +
 builder/src/echarts/chart/bar/BarSeries.js         |    47 +
 builder/src/echarts/chart/bar/BarView.js           |   326 +
 builder/src/echarts/chart/bar/BaseBarSeries.js     |    75 +
 .../src/echarts/chart/bar/PictorialBarSeries.js    |    61 +
 builder/src/echarts/chart/bar/PictorialBarView.js  |   643 ++
 builder/src/echarts/chart/bar/barItemStyle.js      |    33 +
 builder/src/echarts/chart/bar/helper.js            |    39 +
 builder/src/echarts/chart/boxplot.js               |    25 +
 builder/src/echarts/chart/boxplot/BoxplotSeries.js |    92 +
 builder/src/echarts/chart/boxplot/BoxplotView.js   |   143 +
 builder/src/echarts/chart/boxplot/boxplotLayout.js |   176 +
 builder/src/echarts/chart/boxplot/boxplotVisual.js |    41 +
 builder/src/echarts/chart/candlestick.js           |    27 +
 .../echarts/chart/candlestick/CandlestickSeries.js |   104 +
 .../echarts/chart/candlestick/CandlestickView.js   |   251 +
 .../echarts/chart/candlestick/candlestickLayout.js |   179 +
 .../echarts/chart/candlestick/candlestickVisual.js |    69 +
 .../src/echarts/chart/candlestick/preprocessor.js  |    31 +
 builder/src/echarts/chart/chord.js                 |    27 +
 builder/src/echarts/chart/chord/ChordSeries.js     |    69 +
 builder/src/echarts/chart/chord/ChordView.js       |    82 +
 builder/src/echarts/chart/chord/Ribbon.js          |    64 +
 .../src/echarts/chart/chord/chordCircularLayout.js |   133 +
 builder/src/echarts/chart/custom.js                |   493 +
 builder/src/echarts/chart/effectScatter.js         |    25 +
 .../chart/effectScatter/EffectScatterSeries.js     |    63 +
 .../chart/effectScatter/EffectScatterView.js       |    61 +
 builder/src/echarts/chart/funnel.js                |    27 +
 builder/src/echarts/chart/funnel/FunnelSeries.js   |   105 +
 builder/src/echarts/chart/funnel/FunnelView.js     |   180 +
 builder/src/echarts/chart/funnel/funnelLayout.js   |   192 +
 builder/src/echarts/chart/gauge.js                 |    20 +
 builder/src/echarts/chart/gauge/GaugeSeries.js     |   128 +
 builder/src/echarts/chart/gauge/GaugeView.js       |   348 +
 builder/src/echarts/chart/gauge/PointerPath.js     |    45 +
 builder/src/echarts/chart/graph.js                 |    41 +
 builder/src/echarts/chart/graph/GraphSeries.js     |   239 +
 builder/src/echarts/chart/graph/GraphView.js       |   360 +
 builder/src/echarts/chart/graph/adjustEdge.js      |   175 +
 builder/src/echarts/chart/graph/backwardCompat.js  |    18 +
 builder/src/echarts/chart/graph/categoryFilter.js  |    53 +
 builder/src/echarts/chart/graph/categoryVisual.js  |    51 +
 builder/src/echarts/chart/graph/circularLayout.js  |    26 +
 .../echarts/chart/graph/circularLayoutHelper.js    |    61 +
 builder/src/echarts/chart/graph/createView.js      |    82 +
 builder/src/echarts/chart/graph/edgeVisual.js      |    68 +
 builder/src/echarts/chart/graph/forceHelper.js     |   160 +
 builder/src/echarts/chart/graph/forceLayout.js     |   156 +
 builder/src/echarts/chart/graph/graphAction.js     |    71 +
 builder/src/echarts/chart/graph/simpleLayout.js    |    60 +
 .../src/echarts/chart/graph/simpleLayoutHelper.js  |    47 +
 builder/src/echarts/chart/heatmap.js               |    20 +
 builder/src/echarts/chart/heatmap/HeatmapLayer.js  |   165 +
 builder/src/echarts/chart/heatmap/HeatmapSeries.js |    51 +
 builder/src/echarts/chart/heatmap/HeatmapView.js   |   253 +
 builder/src/echarts/chart/helper/EffectLine.js     |   185 +
 builder/src/echarts/chart/helper/EffectPolyline.js |   124 +
 builder/src/echarts/chart/helper/EffectSymbol.js   |   231 +
 builder/src/echarts/chart/helper/LargeLineDraw.js  |   248 +
 .../src/echarts/chart/helper/LargeSymbolDraw.js    |   261 +
 builder/src/echarts/chart/helper/Line.js           |   362 +
 builder/src/echarts/chart/helper/LineDraw.js       |   167 +
 builder/src/echarts/chart/helper/LinePath.js       |    58 +
 builder/src/echarts/chart/helper/Polyline.js       |    92 +
 builder/src/echarts/chart/helper/Symbol.js         |   353 +
 builder/src/echarts/chart/helper/SymbolDraw.js     |   198 +
 .../chart/helper/createGraphFromNodeEdge.js        |    93 +
 .../chart/helper/createGraphFromNodeMatrix.js      |   114 +
 .../echarts/chart/helper/createListFromArray.js    |   125 +
 .../src/echarts/chart/helper/createListSimply.js   |    48 +
 .../echarts/chart/helper/createRenderPlanner.js    |    35 +
 builder/src/echarts/chart/helper/labelHelper.js    |    42 +
 builder/src/echarts/chart/helper/treeHelper.js     |    71 +
 .../src/echarts/chart/helper/whiskerBoxCommon.js   |   114 +
 builder/src/echarts/chart/line.js                  |    30 +
 builder/src/echarts/chart/line/LineSeries.js       |    80 +
 builder/src/echarts/chart/line/LineView.js         |   722 ++
 builder/src/echarts/chart/line/helper.js           |   108 +
 .../src/echarts/chart/line/lineAnimationDiff.js    |   165 +
 builder/src/echarts/chart/line/poly.js             |   356 +
 builder/src/echarts/chart/lines.js                 |    25 +
 builder/src/echarts/chart/lines/LinesSeries.js     |   294 +
 builder/src/echarts/chart/lines/LinesView.js       |   153 +
 builder/src/echarts/chart/lines/linesLayout.js     |    94 +
 builder/src/echarts/chart/lines/linesVisual.js     |    56 +
 builder/src/echarts/chart/map.js                   |    45 +
 builder/src/echarts/chart/map/MapSeries.js         |   218 +
 builder/src/echarts/chart/map/MapView.js           |   148 +
 builder/src/echarts/chart/map/backwardCompat.js    |    31 +
 builder/src/echarts/chart/map/mapDataStatistic.js  |    93 +
 builder/src/echarts/chart/map/mapSymbolLayout.js   |    65 +
 builder/src/echarts/chart/map/mapVisual.js         |    30 +
 builder/src/echarts/chart/parallel.js              |    24 +
 .../src/echarts/chart/parallel/ParallelSeries.js   |   105 +
 builder/src/echarts/chart/parallel/ParallelView.js |   249 +
 .../src/echarts/chart/parallel/parallelVisual.js   |    56 +
 builder/src/echarts/chart/pictorialBar.js          |    29 +
 builder/src/echarts/chart/pie.js                   |    42 +
 builder/src/echarts/chart/pie/PieSeries.js         |   146 +
 builder/src/echarts/chart/pie/PieView.js           |   328 +
 builder/src/echarts/chart/pie/labelLayout.js       |   227 +
 builder/src/echarts/chart/pie/pieLayout.js         |   142 +
 builder/src/echarts/chart/radar.js                 |    33 +
 builder/src/echarts/chart/radar/RadarSeries.js     |    72 +
 builder/src/echarts/chart/radar/RadarView.js       |   196 +
 builder/src/echarts/chart/radar/backwardCompat.js  |    55 +
 builder/src/echarts/chart/radar/radarLayout.js     |    46 +
 builder/src/echarts/chart/sankey.js                |    26 +
 builder/src/echarts/chart/sankey/SankeySeries.js   |   134 +
 builder/src/echarts/chart/sankey/SankeyView.js     |   199 +
 builder/src/echarts/chart/sankey/sankeyAction.js   |    33 +
 builder/src/echarts/chart/sankey/sankeyLayout.js   |   440 +
 builder/src/echarts/chart/sankey/sankeyVisual.js   |    64 +
 builder/src/echarts/chart/scatter.js               |    45 +
 builder/src/echarts/chart/scatter/ScatterSeries.js |    83 +
 builder/src/echarts/chart/scatter/ScatterView.js   |    89 +
 builder/src/echarts/chart/sunburst.js              |    29 +
 .../src/echarts/chart/sunburst/SunburstPiece.js    |   362 +
 .../src/echarts/chart/sunburst/SunburstSeries.js   |   173 +
 builder/src/echarts/chart/sunburst/SunburstView.js |   218 +
 .../src/echarts/chart/sunburst/sunburstAction.js   |    83 +
 .../src/echarts/chart/sunburst/sunburstLayout.js   |   188 +
 builder/src/echarts/chart/themeRiver.js            |    28 +
 .../echarts/chart/themeRiver/ThemeRiverSeries.js   |   297 +
 .../src/echarts/chart/themeRiver/ThemeRiverView.js |   159 +
 .../echarts/chart/themeRiver/themeRiverLayout.js   |   154 +
 .../echarts/chart/themeRiver/themeRiverVisual.js   |    45 +
 builder/src/echarts/chart/tree.js                  |    26 +
 builder/src/echarts/chart/tree/TreeSeries.js       |   138 +
 builder/src/echarts/chart/tree/TreeView.js         |   348 +
 builder/src/echarts/chart/tree/layoutHelper.js     |   286 +
 builder/src/echarts/chart/tree/traversalHelper.js  |    77 +
 builder/src/echarts/chart/tree/treeAction.js       |    35 +
 builder/src/echarts/chart/tree/treeLayout.js       |   123 +
 builder/src/echarts/chart/treemap.js               |    26 +
 builder/src/echarts/chart/treemap/Breadcrumb.js    |   167 +
 builder/src/echarts/chart/treemap/TreemapSeries.js |   370 +
 builder/src/echarts/chart/treemap/TreemapView.js   |   862 ++
 builder/src/echarts/chart/treemap/helper.js        |    71 +
 builder/src/echarts/chart/treemap/treemapAction.js |    61 +
 builder/src/echarts/chart/treemap/treemapLayout.js |   534 +
 builder/src/echarts/chart/treemap/treemapVisual.js |   193 +
 builder/src/echarts/component/angleAxis.js         |    20 +
 builder/src/echarts/component/axis.js              |    20 +
 .../src/echarts/component/axis/AngleAxisView.js    |   236 +
 builder/src/echarts/component/axis/AxisBuilder.js  |   592 ++
 builder/src/echarts/component/axis/AxisView.js     |   111 +
 .../echarts/component/axis/CartesianAxisView.js    |   227 +
 .../src/echarts/component/axis/ParallelAxisView.js |   168 +
 .../src/echarts/component/axis/RadiusAxisView.js   |   149 +
 .../src/echarts/component/axis/SingleAxisView.js   |   108 +
 .../echarts/component/axis/parallelAxisAction.js   |    50 +
 builder/src/echarts/component/axisPointer.js       |    54 +
 .../component/axisPointer/AxisPointerModel.js      |   102 +
 .../component/axisPointer/AxisPointerView.js       |    57 +
 .../component/axisPointer/BaseAxisPointer.js       |   497 +
 .../component/axisPointer/CartesianAxisPointer.js  |   125 +
 .../src/echarts/component/axisPointer/IAxisPointer |    21 +
 .../component/axisPointer/PolarAxisPointer.js      |   123 +
 .../component/axisPointer/SingleAxisPointer.js     |   121 +
 .../echarts/component/axisPointer/axisTrigger.js   |   403 +
 .../component/axisPointer/findPointFromSeries.js   |    67 +
 .../component/axisPointer/globalListener.js        |   134 +
 .../echarts/component/axisPointer/modelHelper.js   |   299 +
 .../echarts/component/axisPointer/viewHelper.js    |   217 +
 builder/src/echarts/component/brush.js             |    30 +
 builder/src/echarts/component/brush/BrushModel.js  |   152 +
 builder/src/echarts/component/brush/BrushView.js   |   105 +
 builder/src/echarts/component/brush/brushAction.js |    68 +
 .../src/echarts/component/brush/preprocessor.js    |    73 +
 builder/src/echarts/component/brush/selector.js    |   136 +
 .../src/echarts/component/brush/visualEncoding.js  |   290 +
 builder/src/echarts/component/calendar.js          |    26 +
 .../src/echarts/component/calendar/CalendarView.js |   423 +
 builder/src/echarts/component/dataZoom.js          |    31 +
 .../src/echarts/component/dataZoom/AxisProxy.js    |   470 +
 .../echarts/component/dataZoom/DataZoomModel.js    |   537 +
 .../src/echarts/component/dataZoom/DataZoomView.js |    82 +
 .../echarts/component/dataZoom/InsideZoomModel.js  |    37 +
 .../echarts/component/dataZoom/InsideZoomView.js   |   211 +
 .../echarts/component/dataZoom/SelectZoomModel.js  |    22 +
 .../echarts/component/dataZoom/SelectZoomView.js   |    22 +
 .../echarts/component/dataZoom/SliderZoomModel.js  |    86 +
 .../echarts/component/dataZoom/SliderZoomView.js   |   726 ++
 .../echarts/component/dataZoom/dataZoomAction.js   |    41 +
 .../component/dataZoom/dataZoomProcessor.js        |    81 +
 builder/src/echarts/component/dataZoom/helper.js   |   144 +
 builder/src/echarts/component/dataZoom/history.js  |   115 +
 builder/src/echarts/component/dataZoom/roams.js    |   201 +
 .../echarts/component/dataZoom/typeDefaulter.js    |    23 +
 builder/src/echarts/component/dataZoomInside.js    |    29 +
 builder/src/echarts/component/dataZoomSelect.js    |    29 +
 builder/src/echarts/component/dataset.js           |    52 +
 builder/src/echarts/component/geo.js               |    58 +
 builder/src/echarts/component/geo/GeoView.js       |    47 +
 builder/src/echarts/component/graphic.js           |   456 +
 builder/src/echarts/component/grid.js              |    21 +
 builder/src/echarts/component/gridSimple.js        |    47 +
 .../echarts/component/helper/BrushController.js    |   876 ++
 .../echarts/component/helper/BrushTargetManager.js |   390 +
 builder/src/echarts/component/helper/MapDraw.js    |   343 +
 .../src/echarts/component/helper/RoamController.js |   200 +
 .../src/echarts/component/helper/brushHelper.js    |    46 +
 .../src/echarts/component/helper/cursorHelper.js   |    34 +
 .../echarts/component/helper/interactionMutex.js   |    53 +
 .../src/echarts/component/helper/listComponent.js  |    62 +
 builder/src/echarts/component/helper/roamHelper.js |    64 +
 .../echarts/component/helper/selectableMixin.js    |   102 +
 builder/src/echarts/component/helper/sliderMove.js |    98 +
 builder/src/echarts/component/legend.js            |    31 +
 .../src/echarts/component/legend/LegendModel.js    |   228 +
 builder/src/echarts/component/legend/LegendView.js |   304 +
 .../component/legend/ScrollableLegendModel.js      |    89 +
 .../component/legend/ScrollableLegendView.js       |   348 +
 .../src/echarts/component/legend/legendAction.js   |    88 +
 .../src/echarts/component/legend/legendFilter.js   |    37 +
 .../component/legend/scrollableLegendAction.js     |    36 +
 builder/src/echarts/component/legendScroll.js      |    26 +
 builder/src/echarts/component/markArea.js          |    25 +
 builder/src/echarts/component/markLine.js          |    25 +
 builder/src/echarts/component/markPoint.js         |    26 +
 .../src/echarts/component/marker/MarkAreaModel.js  |    48 +
 .../src/echarts/component/marker/MarkAreaView.js   |   293 +
 .../src/echarts/component/marker/MarkLineModel.js  |    49 +
 .../src/echarts/component/marker/MarkLineView.js   |   336 +
 .../src/echarts/component/marker/MarkPointModel.js |    45 +
 .../src/echarts/component/marker/MarkPointView.js  |   155 +
 .../src/echarts/component/marker/MarkerModel.js    |   135 +
 builder/src/echarts/component/marker/MarkerView.js |    46 +
 .../src/echarts/component/marker/markerHelper.js   |   217 +
 builder/src/echarts/component/parallel.js          |   114 +
 builder/src/echarts/component/parallelAxis.js      |    21 +
 builder/src/echarts/component/polar.js             |    32 +
 builder/src/echarts/component/radar.js             |    21 +
 builder/src/echarts/component/radar/RadarView.js   |   178 +
 builder/src/echarts/component/radiusAxis.js        |    20 +
 builder/src/echarts/component/singleAxis.js        |    27 +
 builder/src/echarts/component/timeline.js          |    29 +
 .../component/timeline/SliderTimelineModel.js      |   118 +
 .../component/timeline/SliderTimelineView.js       |   615 ++
 .../src/echarts/component/timeline/TimelineAxis.js |    70 +
 .../echarts/component/timeline/TimelineModel.js    |   196 +
 .../src/echarts/component/timeline/TimelineView.js |    22 +
 .../src/echarts/component/timeline/preprocessor.js |   101 +
 .../echarts/component/timeline/timelineAction.js   |    52 +
 .../echarts/component/timeline/typeDefaulter.js    |    23 +
 builder/src/echarts/component/title.js             |   205 +
 builder/src/echarts/component/toolbox.js           |    25 +
 .../src/echarts/component/toolbox/ToolboxModel.js  |    65 +
 .../src/echarts/component/toolbox/ToolboxView.js   |   232 +
 .../src/echarts/component/toolbox/feature/Brush.js |   123 +
 .../echarts/component/toolbox/feature/DataView.js  |   485 +
 .../echarts/component/toolbox/feature/DataZoom.js  |   296 +
 .../echarts/component/toolbox/feature/MagicType.js |   183 +
 .../echarts/component/toolbox/feature/Restore.js   |    52 +
 .../component/toolbox/feature/SaveAsImage.js       |    88 +
 .../echarts/component/toolbox/featureManager.js    |    25 +
 builder/src/echarts/component/tooltip.js           |    44 +
 .../echarts/component/tooltip/TooltipContent.js    |   244 +
 .../component/tooltip/TooltipContentManager.js     |   103 +
 .../src/echarts/component/tooltip/TooltipModel.js  |    93 +
 .../src/echarts/component/tooltip/TooltipView.js   |   717 ++
 builder/src/echarts/component/visualMap.js         |    24 +
 .../echarts/component/visualMap/ContinuousModel.js |   250 +
 .../echarts/component/visualMap/ContinuousView.js  |   766 ++
 .../echarts/component/visualMap/PiecewiseModel.js  |   512 +
 .../echarts/component/visualMap/PiecewiseView.js   |   210 +
 .../echarts/component/visualMap/VisualMapModel.js  |   514 +
 .../echarts/component/visualMap/VisualMapView.js   |   163 +
 builder/src/echarts/component/visualMap/helper.js  |    69 +
 .../echarts/component/visualMap/preprocessor.js    |    59 +
 .../echarts/component/visualMap/typeDefaulter.js   |    23 +
 .../echarts/component/visualMap/visualEncoding.js  |    92 +
 .../echarts/component/visualMap/visualMapAction.js |    33 +
 .../src/echarts/component/visualMapContinuous.js   |    30 +
 .../src/echarts/component/visualMapPiecewise.js    |    30 +
 builder/src/echarts/config.js                      |    37 +
 builder/src/echarts/coord/Axis.js                  |   329 +
 builder/src/echarts/coord/ICoordinateSystem        |    66 +
 builder/src/echarts/coord/View.js                  |   288 +
 builder/src/echarts/coord/axisDefault.js           |   169 +
 builder/src/echarts/coord/axisHelper.js            |   354 +
 builder/src/echarts/coord/axisModelCommonMixin.js  |    82 +
 builder/src/echarts/coord/axisModelCreator.js      |    88 +
 builder/src/echarts/coord/axisTickLabelBuilder.js  |   337 +
 builder/src/echarts/coord/calendar/Calendar.js     |   403 +
 .../src/echarts/coord/calendar/CalendarModel.js    |   135 +
 .../src/echarts/coord/calendar/prepareCustom.js    |    44 +
 builder/src/echarts/coord/cartesian/Axis2D.js      |   124 +
 builder/src/echarts/coord/cartesian/AxisModel.js   |    82 +
 builder/src/echarts/coord/cartesian/Cartesian.js   |   118 +
 builder/src/echarts/coord/cartesian/Cartesian2D.js |   120 +
 builder/src/echarts/coord/cartesian/Grid.js        |   561 +
 builder/src/echarts/coord/cartesian/GridModel.js   |    48 +
 .../echarts/coord/cartesian/cartesianAxisHelper.js |    85 +
 .../src/echarts/coord/cartesian/prepareCustom.js   |    51 +
 builder/src/echarts/coord/geo/Geo.js               |   228 +
 builder/src/echarts/coord/geo/GeoModel.js          |   139 +
 builder/src/echarts/coord/geo/Region.js            |   177 +
 builder/src/echarts/coord/geo/fix/diaoyuIsland.js  |    35 +
 builder/src/echarts/coord/geo/fix/geoCoord.js      |    35 +
 builder/src/echarts/coord/geo/fix/nanhai.js        |    43 +
 builder/src/echarts/coord/geo/fix/textCoord.js     |    39 +
 builder/src/echarts/coord/geo/geoCreator.js        |   206 +
 builder/src/echarts/coord/geo/parseGeoJson.js      |   131 +
 builder/src/echarts/coord/geo/prepareCustom.js     |    55 +
 builder/src/echarts/coord/parallel/AxisModel.js    |   130 +
 builder/src/echarts/coord/parallel/Parallel.js     |   486 +
 builder/src/echarts/coord/parallel/ParallelAxis.js |    67 +
 .../src/echarts/coord/parallel/ParallelModel.js    |   124 +
 .../src/echarts/coord/parallel/parallelCreator.js  |    52 +
 .../echarts/coord/parallel/parallelPreprocessor.js |    66 +
 builder/src/echarts/coord/polar/AngleAxis.js       |    50 +
 builder/src/echarts/coord/polar/AxisModel.js       |    67 +
 builder/src/echarts/coord/polar/Polar.js           |   236 +
 builder/src/echarts/coord/polar/PolarModel.js      |    50 +
 builder/src/echarts/coord/polar/RadiusAxis.js      |    49 +
 builder/src/echarts/coord/polar/polarCreator.js    |   136 +
 builder/src/echarts/coord/polar/prepareCustom.js   |    62 +
 builder/src/echarts/coord/radar/IndicatorAxis.js   |    49 +
 builder/src/echarts/coord/radar/Radar.js           |   241 +
 builder/src/echarts/coord/radar/RadarModel.js      |   131 +
 builder/src/echarts/coord/single/AxisModel.js      |    91 +
 builder/src/echarts/coord/single/Single.js         |   259 +
 builder/src/echarts/coord/single/SingleAxis.js     |   104 +
 builder/src/echarts/coord/single/prepareCustom.js  |    47 +
 .../src/echarts/coord/single/singleAxisHelper.js   |    74 +
 builder/src/echarts/coord/single/singleCreator.js  |    58 +
 builder/src/echarts/data/DataDiffer.js             |   142 +
 builder/src/echarts/data/Graph.js                  |   550 +
 builder/src/echarts/data/List.js                   |  1938 ++++
 builder/src/echarts/data/OrdinalMeta.js            |   141 +
 builder/src/echarts/data/Source.js                 |   137 +
 builder/src/echarts/data/Tree.js                   |   543 +
 .../src/echarts/data/helper/completeDimensions.js  |   259 +
 .../src/echarts/data/helper/createDimensions.js    |    46 +
 builder/src/echarts/data/helper/dataProvider.js    |   327 +
 builder/src/echarts/data/helper/dataStackHelper.js |   152 +
 builder/src/echarts/data/helper/dimensionHelper.js |   123 +
 builder/src/echarts/data/helper/linkList.js        |   145 +
 builder/src/echarts/data/helper/sourceHelper.js    |   524 +
 builder/src/echarts/data/helper/sourceType.js      |    28 +
 builder/src/echarts/echarts.js                     |  1968 ++++
 builder/src/echarts/export.js                      |    53 +
 builder/src/echarts/helper.js                      |    99 +
 builder/src/echarts/lang.js                        |   115 +
 builder/src/echarts/langEN.js                      |    57 +
 builder/src/echarts/langFI.js                      |    57 +
 builder/src/echarts/langTH.js                      |    57 +
 builder/src/echarts/layout/barGrid.js              |   399 +
 builder/src/echarts/layout/barPolar.js             |   262 +
 builder/src/echarts/layout/points.js               |    87 +
 builder/src/echarts/loading/default.js             |   107 +
 builder/src/echarts/model/Component.js             |   211 +
 builder/src/echarts/model/Global.js                |   678 ++
 builder/src/echarts/model/Model.js                 |   204 +
 builder/src/echarts/model/OptionManager.js         |   429 +
 builder/src/echarts/model/Series.js                |   513 +
 builder/src/echarts/model/globalDefault.js         |    68 +
 builder/src/echarts/model/mixin/areaStyle.js       |    25 +
 builder/src/echarts/model/mixin/boxLayout.js       |    30 +
 builder/src/echarts/model/mixin/colorPalette.js    |    76 +
 builder/src/echarts/model/mixin/dataFormat.js      |   115 +
 builder/src/echarts/model/mixin/itemStyle.js       |    32 +
 builder/src/echarts/model/mixin/lineStyle.js       |    38 +
 builder/src/echarts/model/mixin/makeStyleMapper.js |    49 +
 builder/src/echarts/model/mixin/textStyle.js       |    48 +
 builder/src/echarts/model/referHelper.js           |   131 +
 builder/src/echarts/preprocessor/backwardCompat.js |   111 +
 .../src/echarts/preprocessor/helper/compatStyle.js |   295 +
 builder/src/echarts/processor/dataFilter.js        |    45 +
 builder/src/echarts/processor/dataSample.js        |   109 +
 builder/src/echarts/processor/dataStack.js         |   112 +
 builder/src/echarts/scale/Interval.js              |   198 +
 builder/src/echarts/scale/Log.js                   |   180 +
 builder/src/echarts/scale/Ordinal.js               |   125 +
 builder/src/echarts/scale/Scale.js                 |   173 +
 builder/src/echarts/scale/Time.js                  |   207 +
 builder/src/echarts/scale/helper.js                |   118 +
 builder/src/echarts/stream/Scheduler.js            |   526 +
 builder/src/echarts/stream/task.js                 |   314 +
 builder/src/echarts/theme/dark.js                  |   148 +
 builder/src/echarts/theme/light.js                 |    23 +
 builder/src/echarts/util/KDTree.js                 |   268 +
 builder/src/echarts/util/animation.js              |   115 +
 builder/src/echarts/util/array/nest.js             |   125 +
 builder/src/echarts/util/clazz.js                  |   247 +
 builder/src/echarts/util/component.js              |   189 +
 builder/src/echarts/util/format.js                 |   189 +
 builder/src/echarts/util/graphic.js                |  1007 ++
 builder/src/echarts/util/layout.js                 |   478 +
 builder/src/echarts/util/model.js                  |   460 +
 builder/src/echarts/util/number.js                 |   474 +
 builder/src/echarts/util/quickSelect.js            |   102 +
 builder/src/echarts/util/symbol.js                 |   314 +
 builder/src/echarts/util/throttle.js               |   167 +
 builder/src/echarts/view/Chart.js                  |   239 +
 builder/src/echarts/view/Component.js              |    54 +
 builder/src/echarts/visual/VisualMapping.js        |   586 +
 builder/src/echarts/visual/aria.js                 |   146 +
 builder/src/echarts/visual/dataColor.js            |    65 +
 builder/src/echarts/visual/seriesColor.js          |    55 +
 builder/src/echarts/visual/symbol.js               |    77 +
 builder/src/echarts/visual/visualDefault.js        |    67 +
 builder/src/echarts/visual/visualSolution.js       |   207 +
 builder/src/echarts3/CoordinateSystem.js           |    37 +
 builder/src/echarts3/ExtensionAPI.js               |    10 +
 .../src/echarts3/action/createDataSelectAction.js  |    36 +
 builder/src/echarts3/action/geoRoam.js             |    42 +
 builder/src/echarts3/action/roamHelper.js          |    45 +
 builder/src/echarts3/chart/bar.js                  |    16 +
 builder/src/echarts3/chart/bar/BarSeries.js        |     6 +
 builder/src/echarts3/chart/bar/BarView.js          |   222 +
 builder/src/echarts3/chart/bar/BaseBarSeries.js    |    58 +
 .../src/echarts3/chart/bar/PictorialBarSeries.js   |    43 +
 builder/src/echarts3/chart/bar/PictorialBarView.js |   625 ++
 builder/src/echarts3/chart/bar/barItemStyle.js     |    15 +
 builder/src/echarts3/chart/bar/helper.js           |    20 +
 builder/src/echarts3/chart/boxplot.js              |     7 +
 .../src/echarts3/chart/boxplot/BoxplotSeries.js    |    59 +
 builder/src/echarts3/chart/boxplot/BoxplotView.js  |    35 +
 .../src/echarts3/chart/boxplot/boxplotLayout.js    |   170 +
 .../src/echarts3/chart/boxplot/boxplotVisual.js    |    23 +
 builder/src/echarts3/chart/candlestick.js          |     9 +
 .../chart/candlestick/CandlestickSeries.js         |    71 +
 .../echarts3/chart/candlestick/CandlestickView.js  |    36 +
 .../chart/candlestick/candlestickLayout.js         |   122 +
 .../chart/candlestick/candlestickVisual.js         |    23 +
 .../src/echarts3/chart/candlestick/preprocessor.js |    13 +
 builder/src/echarts3/chart/chord.js                |    10 +
 builder/src/echarts3/chart/chord/ChordSeries.js    |    53 +
 builder/src/echarts3/chart/chord/ChordView.js      |    64 +
 builder/src/echarts3/chart/chord/Ribbon.js         |    46 +
 .../echarts3/chart/chord/chordCircularLayout.js    |   114 +
 builder/src/echarts3/chart/custom.js               |   463 +
 builder/src/echarts3/chart/effectScatter.js        |     8 +
 .../chart/effectScatter/EffectScatterSeries.js     |    48 +
 .../chart/effectScatter/EffectScatterView.js       |    22 +
 builder/src/echarts3/chart/funnel.js               |    10 +
 builder/src/echarts3/chart/funnel/FunnelSeries.js  |    97 +
 builder/src/echarts3/chart/funnel/FunnelView.js    |   162 +
 builder/src/echarts3/chart/funnel/funnelLayout.js  |   159 +
 builder/src/echarts3/chart/gauge.js                |     2 +
 builder/src/echarts3/chart/gauge/GaugeSeries.js    |   114 +
 builder/src/echarts3/chart/gauge/GaugeView.js      |   326 +
 builder/src/echarts3/chart/gauge/PointerPath.js    |    27 +
 builder/src/echarts3/chart/graph.js                |    24 +
 builder/src/echarts3/chart/graph/GraphSeries.js    |   224 +
 builder/src/echarts3/chart/graph/GraphView.js      |   342 +
 builder/src/echarts3/chart/graph/adjustEdge.js     |   157 +
 builder/src/echarts3/chart/graph/backwardCompat.js |     0
 builder/src/echarts3/chart/graph/categoryFilter.js |    35 +
 builder/src/echarts3/chart/graph/categoryVisual.js |    33 +
 builder/src/echarts3/chart/graph/circularLayout.js |     8 +
 .../echarts3/chart/graph/circularLayoutHelper.js   |    43 +
 builder/src/echarts3/chart/graph/createView.js     |    64 +
 builder/src/echarts3/chart/graph/edgeVisual.js     |    50 +
 builder/src/echarts3/chart/graph/forceHelper.js    |   135 +
 builder/src/echarts3/chart/graph/forceLayout.js    |   138 +
 builder/src/echarts3/chart/graph/graphAction.js    |    53 +
 builder/src/echarts3/chart/graph/simpleLayout.js   |    37 +
 .../src/echarts3/chart/graph/simpleLayoutHelper.js |    29 +
 builder/src/echarts3/chart/heatmap.js              |     2 +
 builder/src/echarts3/chart/heatmap/HeatmapLayer.js |   146 +
 .../src/echarts3/chart/heatmap/HeatmapSeries.js    |    23 +
 builder/src/echarts3/chart/heatmap/HeatmapView.js  |   211 +
 builder/src/echarts3/chart/helper/EffectLine.js    |   166 +
 .../src/echarts3/chart/helper/EffectPolyline.js    |   105 +
 builder/src/echarts3/chart/helper/EffectSymbol.js  |   212 +
 builder/src/echarts3/chart/helper/LargeLineDraw.js |   121 +
 .../src/echarts3/chart/helper/LargeSymbolDraw.js   |   128 +
 builder/src/echarts3/chart/helper/Line.js          |   341 +
 builder/src/echarts3/chart/helper/LineDraw.js      |    82 +
 builder/src/echarts3/chart/helper/LinePath.js      |    39 +
 builder/src/echarts3/chart/helper/Polyline.js      |    73 +
 builder/src/echarts3/chart/helper/Symbol.js        |   303 +
 builder/src/echarts3/chart/helper/SymbolDraw.js    |   118 +
 .../src/echarts3/chart/helper/WhiskerBoxDraw.js    |   197 +
 .../chart/helper/createGraphFromNodeEdge.js        |    65 +
 .../chart/helper/createGraphFromNodeMatrix.js      |    92 +
 .../echarts3/chart/helper/createListFromArray.js   |   255 +
 builder/src/echarts3/chart/helper/labelHelper.js   |    21 +
 .../src/echarts3/chart/helper/whiskerBoxCommon.js  |    98 +
 builder/src/echarts3/chart/line.js                 |    13 +
 builder/src/echarts3/chart/line/LineSeries.js      |    65 +
 builder/src/echarts3/chart/line/LineView.js        |   653 ++
 .../src/echarts3/chart/line/lineAnimationDiff.js   |   170 +
 builder/src/echarts3/chart/line/poly.js            |   220 +
 builder/src/echarts3/chart/lines.js                |     7 +
 builder/src/echarts3/chart/lines/LinesSeries.js    |   129 +
 builder/src/echarts3/chart/lines/LinesView.js      |    84 +
 builder/src/echarts3/chart/lines/linesLayout.js    |    29 +
 builder/src/echarts3/chart/lines/linesVisual.js    |    32 +
 builder/src/echarts3/chart/map.js                  |    27 +
 builder/src/echarts3/chart/map/MapSeries.js        |   191 +
 builder/src/echarts3/chart/map/MapView.js          |   130 +
 builder/src/echarts3/chart/map/backwardCompat.js   |    13 +
 builder/src/echarts3/chart/map/mapDataStatistic.js |    76 +
 builder/src/echarts3/chart/map/mapSymbolLayout.js  |    47 +
 builder/src/echarts3/chart/map/mapVisual.js        |    12 +
 builder/src/echarts3/chart/parallel.js             |     6 +
 .../src/echarts3/chart/parallel/ParallelSeries.js  |   140 +
 .../src/echarts3/chart/parallel/ParallelView.js    |   218 +
 .../src/echarts3/chart/parallel/parallelVisual.js  |    31 +
 builder/src/echarts3/chart/pictorialBar.js         |    11 +
 builder/src/echarts3/chart/pie.js                  |    24 +
 builder/src/echarts3/chart/pie/PieSeries.js        |   125 +
 builder/src/echarts3/chart/pie/PieView.js          |   311 +
 builder/src/echarts3/chart/pie/labelLayout.js      |   209 +
 builder/src/echarts3/chart/pie/pieLayout.js        |   123 +
 builder/src/echarts3/chart/radar.js                |    16 +
 builder/src/echarts3/chart/radar/RadarSeries.js    |    62 +
 builder/src/echarts3/chart/radar/RadarView.js      |   178 +
 builder/src/echarts3/chart/radar/backwardCompat.js |    37 +
 builder/src/echarts3/chart/radar/radarLayout.js    |    27 +
 builder/src/echarts3/chart/sankey.js               |     7 +
 builder/src/echarts3/chart/sankey/SankeySeries.js  |   112 +
 builder/src/echarts3/chart/sankey/SankeyView.js    |   147 +
 builder/src/echarts3/chart/sankey/sankeyLayout.js  |   394 +
 builder/src/echarts3/chart/sankey/sankeyVisual.js  |    34 +
 builder/src/echarts3/chart/scatter.js              |    10 +
 .../src/echarts3/chart/scatter/ScatterSeries.js    |    48 +
 builder/src/echarts3/chart/scatter/ScatterView.js  |    28 +
 builder/src/echarts3/chart/themeRiver.js           |    11 +
 .../echarts3/chart/themeRiver/ThemeRiverSeries.js  |   281 +
 .../echarts3/chart/themeRiver/ThemeRiverView.js    |   140 +
 .../echarts3/chart/themeRiver/themeRiverLayout.js  |   133 +
 .../echarts3/chart/themeRiver/themeRiverVisual.js  |    26 +
 builder/src/echarts3/chart/tree.js                 |    11 +
 builder/src/echarts3/chart/tree/TreeSeries.js      |   109 +
 builder/src/echarts3/chart/tree/TreeView.js        |   322 +
 builder/src/echarts3/chart/tree/commonLayout.js    |    94 +
 builder/src/echarts3/chart/tree/layoutHelper.js    |   260 +
 .../src/echarts3/chart/tree/orthogonalLayout.js    |     6 +
 builder/src/echarts3/chart/tree/radialLayout.js    |     6 +
 builder/src/echarts3/chart/tree/traversalHelper.js |    58 +
 builder/src/echarts3/chart/tree/treeAction.js      |    17 +
 builder/src/echarts3/chart/treemap.js              |     8 +
 builder/src/echarts3/chart/treemap/Breadcrumb.js   |   149 +
 .../src/echarts3/chart/treemap/TreemapSeries.js    |   359 +
 builder/src/echarts3/chart/treemap/TreemapView.js  |   843 ++
 builder/src/echarts3/chart/treemap/helper.js       |    53 +
 .../src/echarts3/chart/treemap/treemapAction.js    |    41 +
 .../src/echarts3/chart/treemap/treemapLayout.js    |   510 +
 .../src/echarts3/chart/treemap/treemapVisual.js    |   179 +
 builder/src/echarts3/component/angleAxis.js        |     2 +
 builder/src/echarts3/component/axis.js             |     2 +
 .../src/echarts3/component/axis/AngleAxisView.js   |   204 +
 builder/src/echarts3/component/axis/AxisBuilder.js |   607 ++
 builder/src/echarts3/component/axis/AxisView.js    |    93 +
 .../echarts3/component/axis/CartesianAxisView.js   |   195 +
 .../echarts3/component/axis/ParallelAxisView.js    |   150 +
 .../src/echarts3/component/axis/RadiusAxisView.js  |   127 +
 .../src/echarts3/component/axis/SingleAxisView.js  |    97 +
 .../echarts3/component/axis/cartesianAxisHelper.js |    66 +
 .../echarts3/component/axis/parallelAxisAction.js  |    32 +
 .../echarts3/component/axis/singleAxisHelper.js    |    57 +
 builder/src/echarts3/component/axisPointer.js      |    36 +
 .../component/axisPointer/AxisPointerModel.js      |    84 +
 .../component/axisPointer/AxisPointerView.js       |    39 +
 .../component/axisPointer/BaseAxisPointer.js       |   479 +
 .../component/axisPointer/CartesianAxisPointer.js  |   107 +
 .../echarts3/component/axisPointer/IAxisPointer    |    21 +
 .../component/axisPointer/PolarAxisPointer.js      |   105 +
 .../component/axisPointer/SingleAxisPointer.js     |   103 +
 .../echarts3/component/axisPointer/axisTrigger.js  |   384 +
 .../component/axisPointer/findPointFromSeries.js   |    49 +
 .../component/axisPointer/globalListener.js        |   116 +
 .../echarts3/component/axisPointer/modelHelper.js  |   280 +
 .../echarts3/component/axisPointer/viewHelper.js   |   198 +
 builder/src/echarts3/component/brush.js            |    11 +
 builder/src/echarts3/component/brush/BrushModel.js |   128 +
 builder/src/echarts3/component/brush/BrushView.js  |    84 +
 .../src/echarts3/component/brush/brushAction.js    |    49 +
 .../src/echarts3/component/brush/preprocessor.js   |    55 +
 builder/src/echarts3/component/brush/selector.js   |   118 +
 .../src/echarts3/component/brush/visualEncoding.js |   272 +
 builder/src/echarts3/component/calendar.js         |     7 +
 .../echarts3/component/calendar/CalendarView.js    |   405 +
 builder/src/echarts3/component/dataZoom.js         |    12 +
 .../src/echarts3/component/dataZoom/AxisProxy.js   |   426 +
 .../echarts3/component/dataZoom/DataZoomModel.js   |   519 +
 .../echarts3/component/dataZoom/DataZoomView.js    |    64 +
 .../echarts3/component/dataZoom/InsideZoomModel.js |    19 +
 .../echarts3/component/dataZoom/InsideZoomView.js  |   188 +
 .../echarts3/component/dataZoom/SelectZoomModel.js |     4 +
 .../echarts3/component/dataZoom/SelectZoomView.js  |     4 +
 .../echarts3/component/dataZoom/SliderZoomModel.js |    68 +
 .../echarts3/component/dataZoom/SliderZoomView.js  |   701 ++
 .../echarts3/component/dataZoom/dataZoomAction.js  |    23 +
 .../component/dataZoom/dataZoomProcessor.js        |    45 +
 builder/src/echarts3/component/dataZoom/helper.js  |   126 +
 builder/src/echarts3/component/dataZoom/history.js |    97 +
 builder/src/echarts3/component/dataZoom/roams.js   |   191 +
 .../echarts3/component/dataZoom/typeDefaulter.js   |     5 +
 builder/src/echarts3/component/dataZoomInside.js   |    10 +
 builder/src/echarts3/component/dataZoomSelect.js   |    10 +
 builder/src/echarts3/component/geo.js              |    40 +
 builder/src/echarts3/component/geo/GeoView.js      |    29 +
 builder/src/echarts3/component/graphic.js          |   438 +
 builder/src/echarts3/component/grid.js             |     3 +
 builder/src/echarts3/component/gridSimple.js       |    29 +
 .../echarts3/component/helper/BrushController.js   |   859 ++
 .../component/helper/BrushTargetManager.js         |   372 +
 builder/src/echarts3/component/helper/MapDraw.js   |   325 +
 .../echarts3/component/helper/RoamController.js    |   182 +
 .../src/echarts3/component/helper/brushHelper.js   |    28 +
 .../src/echarts3/component/helper/cursorHelper.js  |    16 +
 .../echarts3/component/helper/interactionMutex.js  |    35 +
 .../src/echarts3/component/helper/listComponent.js |    44 +
 .../src/echarts3/component/helper/roamHelper.js    |    45 +
 .../echarts3/component/helper/selectableMixin.js   |    78 +
 .../src/echarts3/component/helper/sliderMove.js    |    79 +
 builder/src/echarts3/component/legend.js           |    13 +
 .../src/echarts3/component/legend/LegendModel.js   |   182 +
 .../src/echarts3/component/legend/LegendView.js    |   275 +
 .../component/legend/ScrollableLegendModel.js      |    71 +
 .../component/legend/ScrollableLegendView.js       |   329 +
 .../src/echarts3/component/legend/legendAction.js  |    70 +
 .../src/echarts3/component/legend/legendFilter.js  |    19 +
 .../component/legend/scrollableLegendAction.js     |    18 +
 builder/src/echarts3/component/legendScroll.js     |     7 +
 builder/src/echarts3/component/markArea.js         |     7 +
 builder/src/echarts3/component/markLine.js         |     7 +
 builder/src/echarts3/component/markPoint.js        |     8 +
 .../src/echarts3/component/marker/MarkAreaModel.js |    32 +
 .../src/echarts3/component/marker/MarkAreaView.js  |   254 +
 .../src/echarts3/component/marker/MarkLineModel.js |    33 +
 .../src/echarts3/component/marker/MarkLineView.js  |   294 +
 .../echarts3/component/marker/MarkPointModel.js    |    29 +
 .../src/echarts3/component/marker/MarkPointView.js |   127 +
 .../src/echarts3/component/marker/MarkerModel.js   |   116 +
 .../src/echarts3/component/marker/MarkerView.js    |    28 +
 .../src/echarts3/component/marker/markerHelper.js  |   165 +
 builder/src/echarts3/component/parallel.js         |    96 +
 builder/src/echarts3/component/parallelAxis.js     |     3 +
 builder/src/echarts3/component/polar.js            |    14 +
 builder/src/echarts3/component/radar.js            |     3 +
 builder/src/echarts3/component/radar/RadarView.js  |   160 +
 builder/src/echarts3/component/radiusAxis.js       |     2 +
 builder/src/echarts3/component/singleAxis.js       |     9 +
 builder/src/echarts3/component/timeline.js         |    10 +
 .../component/timeline/SliderTimelineModel.js      |   104 +
 .../component/timeline/SliderTimelineView.js       |   607 ++
 .../echarts3/component/timeline/TimelineAxis.js    |    81 +
 .../echarts3/component/timeline/TimelineModel.js   |   184 +
 .../echarts3/component/timeline/TimelineView.js    |     4 +
 .../echarts3/component/timeline/preprocessor.js    |    83 +
 .../echarts3/component/timeline/timelineAction.js  |    34 +
 .../echarts3/component/timeline/typeDefaulter.js   |     5 +
 builder/src/echarts3/component/title.js            |   187 +
 builder/src/echarts3/component/toolbox.js          |     7 +
 .../src/echarts3/component/toolbox/ToolboxModel.js |    47 +
 .../src/echarts3/component/toolbox/ToolboxView.js  |   213 +
 .../echarts3/component/toolbox/feature/Brush.js    |   105 +
 .../echarts3/component/toolbox/feature/DataView.js |   467 +
 .../echarts3/component/toolbox/feature/DataZoom.js |   275 +
 .../component/toolbox/feature/MagicType.js         |   165 +
 .../echarts3/component/toolbox/feature/Restore.js  |    34 +
 .../component/toolbox/feature/SaveAsImage.js       |    70 +
 .../echarts3/component/toolbox/featureManager.js   |     7 +
 builder/src/echarts3/component/tooltip.js          |    26 +
 .../echarts3/component/tooltip/TooltipContent.js   |   222 +
 .../component/tooltip/TooltipContentManager.js     |    85 +
 .../src/echarts3/component/tooltip/TooltipModel.js |    75 +
 .../src/echarts3/component/tooltip/TooltipView.js  |   699 ++
 builder/src/echarts3/component/visualMap.js        |     5 +
 .../component/visualMap/ContinuousModel.js         |   232 +
 .../echarts3/component/visualMap/ContinuousView.js |   749 ++
 .../echarts3/component/visualMap/PiecewiseModel.js |   494 +
 .../echarts3/component/visualMap/PiecewiseView.js  |   192 +
 .../echarts3/component/visualMap/VisualMapModel.js |   477 +
 .../echarts3/component/visualMap/VisualMapView.js  |   145 +
 builder/src/echarts3/component/visualMap/helper.js |    51 +
 .../echarts3/component/visualMap/preprocessor.js   |    41 +
 .../echarts3/component/visualMap/typeDefaulter.js  |     5 +
 .../echarts3/component/visualMap/visualEncoding.js |    65 +
 .../component/visualMap/visualMapAction.js         |    15 +
 .../src/echarts3/component/visualMapContinuous.js  |    11 +
 .../src/echarts3/component/visualMapPiecewise.js   |    11 +
 builder/src/echarts3/config.js                     |    19 +
 builder/src/echarts3/coord/Axis.js                 |   260 +
 builder/src/echarts3/coord/ICoordinateSystem       |    64 +
 builder/src/echarts3/coord/View.js                 |   267 +
 builder/src/echarts3/coord/axisDefault.js          |   149 +
 builder/src/echarts3/coord/axisHelper.js           |   249 +
 builder/src/echarts3/coord/axisModelCommonMixin.js |    88 +
 builder/src/echarts3/coord/axisModelCreator.js     |    35 +
 builder/src/echarts3/coord/calendar/Calendar.js    |   385 +
 .../src/echarts3/coord/calendar/CalendarModel.js   |   119 +
 .../src/echarts3/coord/calendar/prepareCustom.js   |    25 +
 builder/src/echarts3/coord/cartesian/Axis2D.js     |   117 +
 builder/src/echarts3/coord/cartesian/AxisModel.js  |    64 +
 builder/src/echarts3/coord/cartesian/Cartesian.js  |    99 +
 .../src/echarts3/coord/cartesian/Cartesian2D.js    |    78 +
 builder/src/echarts3/coord/cartesian/Grid.js       |   582 +
 builder/src/echarts3/coord/cartesian/GridModel.js  |    30 +
 .../src/echarts3/coord/cartesian/prepareCustom.js  |    30 +
 builder/src/echarts3/coord/geo/Geo.js              |   208 +
 builder/src/echarts3/coord/geo/GeoModel.js         |   124 +
 builder/src/echarts3/coord/geo/Region.js           |   158 +
 builder/src/echarts3/coord/geo/fix/diaoyuIsland.js |    17 +
 builder/src/echarts3/coord/geo/fix/geoCoord.js     |    17 +
 builder/src/echarts3/coord/geo/fix/nanhai.js       |    25 +
 builder/src/echarts3/coord/geo/fix/textCoord.js    |    21 +
 builder/src/echarts3/coord/geo/geoCreator.js       |   188 +
 builder/src/echarts3/coord/geo/parseGeoJson.js     |   112 +
 builder/src/echarts3/coord/geo/prepareCustom.js    |    32 +
 builder/src/echarts3/coord/parallel/AxisModel.js   |   103 +
 builder/src/echarts3/coord/parallel/Parallel.js    |   460 +
 .../src/echarts3/coord/parallel/ParallelAxis.js    |    49 +
 .../src/echarts3/coord/parallel/ParallelModel.js   |   106 +
 .../src/echarts3/coord/parallel/parallelCreator.js |    33 +
 .../coord/parallel/parallelPreprocessor.js         |    48 +
 builder/src/echarts3/coord/polar/AngleAxis.js      |    32 +
 builder/src/echarts3/coord/polar/AxisModel.js      |    49 +
 builder/src/echarts3/coord/polar/Polar.js          |   217 +
 builder/src/echarts3/coord/polar/PolarModel.js     |    32 +
 builder/src/echarts3/coord/polar/RadiusAxis.js     |    31 +
 builder/src/echarts3/coord/polar/polarCreator.js   |   114 +
 builder/src/echarts3/coord/polar/prepareCustom.js  |    44 +
 builder/src/echarts3/coord/radar/IndicatorAxis.js  |    31 +
 builder/src/echarts3/coord/radar/Radar.js          |   223 +
 builder/src/echarts3/coord/radar/RadarModel.js     |   113 +
 builder/src/echarts3/coord/single/AxisModel.js     |    73 +
 builder/src/echarts3/coord/single/Single.js        |   240 +
 builder/src/echarts3/coord/single/SingleAxis.js    |    91 +
 builder/src/echarts3/coord/single/prepareCustom.js |    26 +
 builder/src/echarts3/coord/single/singleCreator.js |    39 +
 builder/src/echarts3/data/DataDiffer.js            |   124 +
 builder/src/echarts3/data/Graph.js                 |   528 +
 builder/src/echarts3/data/List.js                  |  1208 +++
 builder/src/echarts3/data/Tree.js                  |   493 +
 .../src/echarts3/data/helper/completeDimensions.js |   215 +
 builder/src/echarts3/data/helper/linkList.js       |   126 +
 builder/src/echarts3/echarts.js                    |  1869 ++++
 builder/src/echarts3/export.js                     |    32 +
 builder/src/echarts3/helper.js                     |    67 +
 builder/src/echarts3/lang.js                       |    39 +
 builder/src/echarts3/langEN.js                     |    39 +
 builder/src/echarts3/langFI.js                     |    39 +
 builder/src/echarts3/layout/barGrid.js             |   289 +
 builder/src/echarts3/layout/barPolar.js            |   248 +
 builder/src/echarts3/layout/points.js              |    29 +
 builder/src/echarts3/loading/default.js            |    89 +
 builder/src/echarts3/model/Component.js            |   177 +
 builder/src/echarts3/model/Global.js               |   633 ++
 builder/src/echarts3/model/Model.js                |   183 +
 builder/src/echarts3/model/OptionManager.js        |   400 +
 builder/src/echarts3/model/Series.js               |   305 +
 builder/src/echarts3/model/globalDefault.js        |    51 +
 builder/src/echarts3/model/mixin/areaStyle.js      |     7 +
 builder/src/echarts3/model/mixin/boxLayout.js      |    12 +
 builder/src/echarts3/model/mixin/colorPalette.js   |    31 +
 builder/src/echarts3/model/mixin/itemStyle.js      |    14 +
 builder/src/echarts3/model/mixin/lineStyle.js      |    20 +
 .../src/echarts3/model/mixin/makeStyleMapper.js    |    31 +
 builder/src/echarts3/model/mixin/textStyle.js      |    30 +
 .../src/echarts3/preprocessor/backwardCompat.js    |    99 +
 .../echarts3/preprocessor/helper/compatStyle.js    |   178 +
 builder/src/echarts3/processor/dataFilter.js       |    24 +
 builder/src/echarts3/processor/dataSample.js       |    85 +
 builder/src/echarts3/scale/Interval.js             |   193 +
 builder/src/echarts3/scale/Log.js                  |   161 +
 builder/src/echarts3/scale/Ordinal.js              |    87 +
 builder/src/echarts3/scale/Scale.js                |   162 +
 builder/src/echarts3/scale/Time.js                 |   183 +
 builder/src/echarts3/scale/helper.js               |    99 +
 builder/src/echarts3/util/KDTree.js                |   249 +
 builder/src/echarts3/util/animation.js             |    97 +
 builder/src/echarts3/util/array/nest.js            |   101 +
 builder/src/echarts3/util/clazz.js                 |   242 +
 builder/src/echarts3/util/component.js             |   172 +
 builder/src/echarts3/util/format.js                |   151 +
 builder/src/echarts3/util/graphic.js               |   981 ++
 builder/src/echarts3/util/layout.js                |   460 +
 builder/src/echarts3/util/model.js                 |   610 ++
 builder/src/echarts3/util/number.js                |   456 +
 builder/src/echarts3/util/quickSelect.js           |    83 +
 builder/src/echarts3/util/symbol.js                |   296 +
 builder/src/echarts3/util/throttle.js              |   142 +
 builder/src/echarts3/view/Chart.js                 |   137 +
 builder/src/echarts3/view/Component.js             |    36 +
 builder/src/echarts3/visual/VisualMapping.js       |   559 +
 builder/src/echarts3/visual/dataColor.js           |    39 +
 builder/src/echarts3/visual/seriesColor.js         |    32 +
 builder/src/echarts3/visual/symbol.js              |    39 +
 builder/src/echarts3/visual/visualDefault.js       |    48 +
 builder/src/echarts3/visual/visualSolution.js      |   134 +
 builder/src/zrender/Element.js                     |   264 +
 builder/src/zrender/Handler.js                     |   320 +
 builder/src/zrender/Layer.js                       |   227 +
 builder/src/zrender/Painter.js                     |   992 ++
 builder/src/zrender/Storage.js                     |   228 +
 builder/src/zrender/animation/Animation.js         |   240 +
 builder/src/zrender/animation/Animator.js          |   638 ++
 builder/src/zrender/animation/Clip.js              |   100 +
 builder/src/zrender/animation/easing.js            |   377 +
 .../src/zrender/animation/requestAnimationFrame.js |     4 +
 builder/src/zrender/config.js                      |    22 +
 builder/src/zrender/contain/arc.js                 |    56 +
 builder/src/zrender/contain/cubic.js               |    31 +
 builder/src/zrender/contain/line.js                |    37 +
 builder/src/zrender/contain/path.js                |   381 +
 builder/src/zrender/contain/polygon.js             |    30 +
 builder/src/zrender/contain/quadratic.js           |    29 +
 builder/src/zrender/contain/text.js                |   658 ++
 builder/src/zrender/contain/util.js                |    10 +
 builder/src/zrender/contain/windingLine.js         |    21 +
 builder/src/zrender/container/Group.js             |   308 +
 builder/src/zrender/core/BoundingRect.js           |   180 +
 builder/src/zrender/core/GestureMgr.js             |    98 +
 builder/src/zrender/core/LRU.js                    |   201 +
 builder/src/zrender/core/PathProxy.js              |   755 ++
 builder/src/zrender/core/arrayDiff.js              |   207 +
 builder/src/zrender/core/arrayDiff2.js             |   195 +
 builder/src/zrender/core/bbox.js                   |   209 +
 builder/src/zrender/core/curve.js                  |   504 +
 builder/src/zrender/core/env.js                    |   157 +
 builder/src/zrender/core/event.js                  |   161 +
 builder/src/zrender/core/guid.js                   |     9 +
 builder/src/zrender/core/log.js                    |    19 +
 builder/src/zrender/core/matrix.js                 |   165 +
 builder/src/zrender/core/timsort.js                |   662 ++
 builder/src/zrender/core/util.js                   |   653 ++
 builder/src/zrender/core/vector.js                 |   267 +
 builder/src/zrender/dom/HandlerProxy.js            |   323 +
 builder/src/zrender/export.js                      |    39 +
 builder/src/zrender/graphic/CompoundPath.js        |    53 +
 builder/src/zrender/graphic/Displayable.js         |   251 +
 builder/src/zrender/graphic/Gradient.js            |    17 +
 builder/src/zrender/graphic/Image.js               |    88 +
 .../src/zrender/graphic/IncrementalDisplayable.js  |   141 +
 builder/src/zrender/graphic/LinearGradient.js      |    32 +
 builder/src/zrender/graphic/Path.js                |   344 +
 builder/src/zrender/graphic/Pattern.js             |    14 +
 builder/src/zrender/graphic/RadialGradient.js      |    30 +
 builder/src/zrender/graphic/States.js              |   391 +
 builder/src/zrender/graphic/Style.js               |   452 +
 builder/src/zrender/graphic/Text.js                |    67 +
 .../zrender/graphic/helper/fixClipWithShadow.js    |    52 +
 builder/src/zrender/graphic/helper/fixShadow.js    |    18 +
 builder/src/zrender/graphic/helper/image.js        |    82 +
 builder/src/zrender/graphic/helper/poly.js         |    33 +
 builder/src/zrender/graphic/helper/roundRect.js    |    79 +
 builder/src/zrender/graphic/helper/smoothBezier.js |    93 +
 builder/src/zrender/graphic/helper/smoothSpline.js |    63 +
 builder/src/zrender/graphic/helper/text.js         |   414 +
 builder/src/zrender/graphic/mixin/RectText.js      |    52 +
 builder/src/zrender/graphic/mixin/Stateful.js      |    29 +
 builder/src/zrender/graphic/shape/Arc.js           |    32 +
 builder/src/zrender/graphic/shape/BezierCurve.js   |   101 +
 builder/src/zrender/graphic/shape/Circle.js        |    29 +
 builder/src/zrender/graphic/shape/Droplet.js       |    24 +
 builder/src/zrender/graphic/shape/Ellipse.js       |    32 +
 builder/src/zrender/graphic/shape/Heart.js         |    23 +
 builder/src/zrender/graphic/shape/Isogon.js        |    39 +
 builder/src/zrender/graphic/shape/Line.js          |    51 +
 builder/src/zrender/graphic/shape/Polygon.js       |    17 +
 builder/src/zrender/graphic/shape/Polyline.js      |    20 +
 builder/src/zrender/graphic/shape/Rect.js          |    36 +
 builder/src/zrender/graphic/shape/Ring.js          |    23 +
 builder/src/zrender/graphic/shape/Rose.js          |    43 +
 builder/src/zrender/graphic/shape/Sector.js        |    40 +
 builder/src/zrender/graphic/shape/Star.js          |    53 +
 builder/src/zrender/graphic/shape/Trochoid.js      |    57 +
 builder/src/zrender/mixin/Animatable.js            |   245 +
 builder/src/zrender/mixin/Draggable.js             |    78 +
 builder/src/zrender/mixin/Eventful.js              |   327 +
 builder/src/zrender/mixin/Transformable.js         |   280 +
 builder/src/zrender/svg/Painter.js                 |   343 +
 builder/src/zrender/svg/core.js                    |     4 +
 builder/src/zrender/svg/graphic.js                 |   511 +
 builder/src/zrender/svg/helper/ClippathManager.js  |   152 +
 builder/src/zrender/svg/helper/Definable.js        |   253 +
 builder/src/zrender/svg/helper/GradientManager.js  |   186 +
 builder/src/zrender/svg/helper/ShadowManager.js    |   185 +
 builder/src/zrender/svg/svg.js                     |     4 +
 builder/src/zrender/tool/color.js                  |   608 ++
 builder/src/zrender/tool/path.js                   |   400 +
 builder/src/zrender/tool/transformPath.js          |    94 +
 builder/src/zrender/vml/Painter.js                 |   170 +
 builder/src/zrender/vml/core.js                    |    41 +
 builder/src/zrender/vml/graphic.js                 |   997 ++
 builder/src/zrender/vml/vml.js                     |     4 +
 builder/src/zrender/zrender.js                     |   438 +
 builder/src/zrender3/Element.js                    |   258 +
 builder/src/zrender3/Handler.js                    |   316 +
 builder/src/zrender3/Layer.js                      |   214 +
 builder/src/zrender3/Painter.js                    |  1048 ++
 builder/src/zrender3/Storage.js                    |   236 +
 builder/src/zrender3/animation/Animation.js        |   231 +
 builder/src/zrender3/animation/Animator.js         |   638 ++
 builder/src/zrender3/animation/Clip.js             |   100 +
 builder/src/zrender3/animation/easing.js           |   377 +
 .../zrender3/animation/requestAnimationFrame.js    |     4 +
 builder/src/zrender3/config.js                     |    22 +
 builder/src/zrender3/contain/arc.js                |    56 +
 builder/src/zrender3/contain/cubic.js              |    31 +
 builder/src/zrender3/contain/line.js               |    37 +
 builder/src/zrender3/contain/path.js               |   381 +
 builder/src/zrender3/contain/polygon.js            |    30 +
 builder/src/zrender3/contain/quadratic.js          |    29 +
 builder/src/zrender3/contain/text.js               |   657 ++
 builder/src/zrender3/contain/util.js               |    10 +
 builder/src/zrender3/contain/windingLine.js        |    20 +
 builder/src/zrender3/container/Group.js            |   308 +
 builder/src/zrender3/core/BoundingRect.js          |   180 +
 builder/src/zrender3/core/GestureMgr.js            |    98 +
 builder/src/zrender3/core/LRU.js                   |   201 +
 builder/src/zrender3/core/PathProxy.js             |   755 ++
 builder/src/zrender3/core/arrayDiff.js             |   207 +
 builder/src/zrender3/core/arrayDiff2.js            |   195 +
 builder/src/zrender3/core/bbox.js                  |   209 +
 builder/src/zrender3/core/curve.js                 |   504 +
 builder/src/zrender3/core/env.js                   |   121 +
 builder/src/zrender3/core/event.js                 |   135 +
 builder/src/zrender3/core/guid.js                  |     9 +
 builder/src/zrender3/core/log.js                   |    19 +
 builder/src/zrender3/core/matrix.js                |   155 +
 builder/src/zrender3/core/timsort.js               |   662 ++
 builder/src/zrender3/core/util.js                  |   604 ++
 builder/src/zrender3/core/vector.js                |   267 +
 builder/src/zrender3/dom/HandlerProxy.js           |   323 +
 builder/src/zrender3/export.js                     |    38 +
 builder/src/zrender3/graphic/CompoundPath.js       |    53 +
 builder/src/zrender3/graphic/Displayable.js        |   244 +
 builder/src/zrender3/graphic/Gradient.js           |    17 +
 builder/src/zrender3/graphic/Image.js              |    87 +
 builder/src/zrender3/graphic/LinearGradient.js     |    32 +
 builder/src/zrender3/graphic/Path.js               |   343 +
 builder/src/zrender3/graphic/Pattern.js            |    14 +
 builder/src/zrender3/graphic/RadialGradient.js     |    30 +
 builder/src/zrender3/graphic/States.js             |   391 +
 builder/src/zrender3/graphic/Style.js              |   446 +
 builder/src/zrender3/graphic/Text.js               |    67 +
 .../zrender3/graphic/helper/fixClipWithShadow.js   |    52 +
 builder/src/zrender3/graphic/helper/image.js       |    82 +
 builder/src/zrender3/graphic/helper/poly.js        |    33 +
 builder/src/zrender3/graphic/helper/roundRect.js   |    79 +
 .../src/zrender3/graphic/helper/smoothBezier.js    |    93 +
 .../src/zrender3/graphic/helper/smoothSpline.js    |    63 +
 builder/src/zrender3/graphic/helper/text.js        |   417 +
 builder/src/zrender3/graphic/mixin/RectText.js     |    52 +
 builder/src/zrender3/graphic/mixin/Stateful.js     |    29 +
 builder/src/zrender3/graphic/shape/Arc.js          |    32 +
 builder/src/zrender3/graphic/shape/BezierCurve.js  |   101 +
 builder/src/zrender3/graphic/shape/Circle.js       |    29 +
 builder/src/zrender3/graphic/shape/Droplet.js      |    24 +
 builder/src/zrender3/graphic/shape/Ellipse.js      |    32 +
 builder/src/zrender3/graphic/shape/Heart.js        |    23 +
 builder/src/zrender3/graphic/shape/Isogon.js       |    39 +
 builder/src/zrender3/graphic/shape/Line.js         |    51 +
 builder/src/zrender3/graphic/shape/Polygon.js      |    17 +
 builder/src/zrender3/graphic/shape/Polyline.js     |    20 +
 builder/src/zrender3/graphic/shape/Rect.js         |    36 +
 builder/src/zrender3/graphic/shape/Ring.js         |    23 +
 builder/src/zrender3/graphic/shape/Rose.js         |    43 +
 builder/src/zrender3/graphic/shape/Sector.js       |    40 +
 builder/src/zrender3/graphic/shape/Star.js         |    53 +
 builder/src/zrender3/graphic/shape/Trochoid.js     |    57 +
 builder/src/zrender3/mixin/Animatable.js           |   245 +
 builder/src/zrender3/mixin/Draggable.js            |    78 +
 builder/src/zrender3/mixin/Eventful.js             |   327 +
 builder/src/zrender3/mixin/Transformable.js        |   280 +
 builder/src/zrender3/svg/Painter.js                |   303 +
 builder/src/zrender3/svg/core.js                   |     4 +
 builder/src/zrender3/svg/graphic.js                |   488 +
 builder/src/zrender3/svg/helper/ClippathManager.js |   150 +
 builder/src/zrender3/svg/helper/Definable.js       |   246 +
 builder/src/zrender3/svg/helper/GradientManager.js |   185 +
 builder/src/zrender3/svg/svg.js                    |     4 +
 builder/src/zrender3/tool/color.js                 |   602 ++
 builder/src/zrender3/tool/path.js                  |   400 +
 builder/src/zrender3/tool/transformPath.js         |    94 +
 builder/src/zrender3/vml/Painter.js                |   170 +
 builder/src/zrender3/vml/core.js                   |    41 +
 builder/src/zrender3/vml/graphic.js                |   997 ++
 builder/src/zrender3/vml/vml.js                    |     4 +
 builder/src/zrender3/zrender.js                    |   417 +
 builder/text.js                                    |    46 +
 changelog.html                                     |     5 +-
 coding-standard.html                               |    14 +-
 committers.html                                    |     5 +-
 css/main.css                                       |     2 +-
 dependencies.html                                  |     5 +-
 download.html                                      |     5 +-
 faq.html                                           |     5 +-
 index.html                                         |    37 +-
 js/chart-list.js                                   |    57 +-
 js/common-nav.js                                   |     1 -
 js/common.js                                       |    71 +-
 js/config.js                                       |   719 +-
 js/docTool/main.js                                 |   794 +-
 js/examples-nav.js                                 |    67 +-
 js/index.js                                        |   795 +-
 js/log.js                                          |    23 +-
 js/spreadsheet/spreadsheet.js                      |   381 +-
 license.html                                       |     5 +-
 maillist.html                                      |     5 +-
 nav.html                                           |     2 +-
 option.html                                        |    26 +-
 option3.html                                       |    75 +
 tutorial.html                                      |    35 +-
 1034 files changed, 182768 insertions(+), 2854 deletions(-)

diff --git a/README.md b/README.md
index ee15266..e654055 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,9 @@
 
 1. Clone this project, alone with [echarts-www](https://github.com/ecomfe/echarts-www) and [echarts-doc](https://github.com/ecomfe/echarts-doc) under the same directory.
 
-2. Run `gulp apache` under `echarts-www` project to generate Website files into this repo.
+2. Run `gulp release-en` under `echarts-www` project to generate Website files into this repo.
 
-3. If documents are changed, run `node build.js` under `echarts-doc` and then run `gulp apache` under `echarts-www`.
+3. If documents are changed, run `sh release.sh` under `echarts-doc` and then run `gulp apache` under `echarts-www`.
 
 4. Commit and push to `asf-site` branch.
 
diff --git a/_common.html b/_common.html
new file mode 100644
index 0000000..6bb1366
--- /dev/null
+++ b/_common.html
@@ -0,0 +1 @@
+<script>window.EC_WWW_LANG = 'en';</script>
\ No newline at end of file
diff --git a/_var.html b/_var.html
new file mode 100644
index 0000000..e69de29
diff --git a/_variablesLang.html b/_variablesLang.html
new file mode 100644
index 0000000..e69de29
diff --git a/api.html b/api.html
index 9c5135b..dbf1067 100644
--- a/api.html
+++ b/api.html
@@ -1,24 +1,23 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1" user-scalable="no"><meta name="description" content="ECharts, a powerful, interactive charting and visualization library for browser"><link rel="shortcut icon" href="images/favicon.png"><link rel="stylesheet" type="text/css" href="./vendors/bootstrap/css/bootstrap.min.css"><!-- HTML5 shim and Respond.js for IE8 [...]
+<!DOCTYPE html><html lang="en-US"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1" user-scalable="no"><meta name="description" content="ECharts, a powerful, interactive charting and visualization library for browser"><link rel="shortcut icon" href="images/favicon.png"><link rel="stylesheet" type="text/css" href="vendors/bootstrap/css/bootstrap.min.css"><!-- HTML5 shim and Respond.js for IE [...]
+</script><script type="text/javascript" src="./vendors/pace/pace.min.js"></script><script id="font-hack" type="text/javascript">if (/windows/i.test(navigator.userAgent)) {
     var el = document.createElement('style');
     el.innerHTML = ''
         + '@font-face {font-family:"noto-thin";src:local("Microsoft Yahei");}'
         + '@font-face {font-family:"noto-light";src:local("Microsoft Yahei");}';
     document.head.insertBefore(el, document.getElementById('font-hack'));
 }
-</script><title>ECharts Documentation</title><link rel="stylesheet" type="text/css" href="css/ecOption.css?_v_=1478158214015"><link rel="stylesheet" type="text/css" href="vendors/prettify/prettify.css"><link rel="stylesheet" type="text/css" href="vendors/perfect-scrollbar/0.6.8/css/perfect-scrollbar.min.css"><link rel="stylesheet" type="text/css" href="vendors/jquery-autocomplete/jquery.auto-complete.css"><script src="js/log.js"></script><script src="vendors/prettify/prettify.js"></scrip [...]
-<body class="lower-ie">
-<![endif]-->
-<!--[if (gt IE 8)|!(IE)]><body class="undefined"></body><![endif]--><div id="lowie-main"><img src="./images/forie.png" alt="ie tip"></div><div id="main">
-    <nav class="navbar navbar-default navbar-fixed-top"><div class="container-fluid"><div class="navbar-header"><button type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false" class="navbar-toggle collapsed"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="./index.html" class="navbar-brand"><img src="./images/logo.png" alt="echarts logo"  [...]
-
-<div class="ecdoc-apidoc"></div></div><script type="text/javascript" src="./vendors/bootstrap/js/bootstrap.min.js"></script><script type="text/javascript" src="./vendors/bootstrap/js/validator.js"></script><script type="text/javascript">window.globalArgsExtra = {
+</script><title>ECharts Documentation</title><link rel="stylesheet" type="text/css" href="css/ecOption.css?_v_=1530784620000"><link rel="stylesheet" type="text/css" href="vendors/prettify/prettify.css"><link rel="stylesheet" type="text/css" href="vendors/perfect-scrollbar/0.6.8/css/perfect-scrollbar.min.css"><link rel="stylesheet" type="text/css" href="vendors/jquery-autocomplete/jquery.auto-complete.css"><link rel="stylesheet" type="text/css" href="vendors/twentytwenty/twentytwenty.css" [...]
+<!--[if (gt IE 8)|!(IE)]><body class="undefined"></body><![endif]--><div id="main"><nav class="navbar navbar-default navbar-fixed-top"><div class="container-fluid"><div class="navbar-header"><button type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false" class="navbar-toggle collapsed"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="./in [...]
     pageName: 'api',
-    schemaUrl: 'documents/en/api.json',
     initHash: 'echarts',
     hideTreeRoot: true,
     docTreeChildrenPre: 'API',
     docTreeChildrenPost: '',
     lang: {
+        cn: {
+            queryBoxTextFuzzyPath: 'API搜索',
+            queryBoxPlaceholderFuzzyPath: 'API名称搜索(快捷键\'/\')'
+        },
         en: {
             queryBoxTextFuzzyPath: 'API search',
             queryBoxPlaceholderFuzzyPath: 'API search (shortcut: \'/\')'
@@ -29,7 +28,7 @@
 var vendorPath = '../vendors';
 
 define('globalArgs', extend({
-    version: '1478158214015',
+    version: '1530784620000',
     basePath: './',
     // Schema url is added by each doc page
     schemaUrl: '',
@@ -64,7 +63,7 @@ require.config({
         hasher: vendorPath + '/hasher/1.2.0/hasher.min',
         perfectScrollbar: vendorPath + '/perfect-scrollbar/0.6.8/js/perfect-scrollbar'
     },
-    urlArgs: '_v_=1478158214015'
+    urlArgs: '_v_=1530784620000'
 });
 
 require(['docTool/main'], function (main) {
@@ -78,4 +77,10 @@ function extend(tar, src) {
         }
     }
     return tar;
-}</script><script type="text/javascript" src="./js/hm.js"></script></html>
+}</script><script type="text/javascript">var _hmt = _hmt || [];
+(function() {
+var hm = document.createElement("script");
+hm.src = "//hm.baidu.com/hm.js?4bad1df23f079e0d12bdbef5e65b072f";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(hm, s);
+})();</script></html>
\ No newline at end of file
diff --git a/builder.html b/builder.html
new file mode 100644
index 0000000..4eadfb7
--- /dev/null
+++ b/builder.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html><html lang="en-US"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1" user-scalable="no"><meta name="description" content="ECharts, a powerful, interactive charting and visualization library for browser"><link rel="shortcut icon" href="images/favicon.png"><link rel="stylesheet" type="text/css" href="vendors/bootstrap/css/bootstrap.min.css"><!-- HTML5 shim and Respond.js for IE [...]
+</script><script type="text/javascript" src="./vendors/pace/pace.min.js"></script><script id="font-hack" type="text/javascript">if (/windows/i.test(navigator.userAgent)) {
+    var el = document.createElement('style');
+    el.innerHTML = ''
+        + '@font-face {font-family:"noto-thin";src:local("Microsoft Yahei");}'
+        + '@font-face {font-family:"noto-light";src:local("Microsoft Yahei");}';
+    document.head.insertBefore(el, document.getElementById('font-hack'));
+}
+</script><title>ECharts Online Builder</title><script type="text/javascript" src="./vendors/jquery/jquery.min.js"></script></head><!--[if lte IE 8]><body class="lower-ie"><div id="lowie-main"><img src="./images/forie.png" alt="ie tip"></div></body><![endif]-->
+<!--[if (gt IE 8)|!(IE)]><body class="undefined"></body><![endif]--><div id="main"><nav class="navbar navbar-default navbar-fixed-top"><div class="container-fluid"><div class="navbar-header"><button type="button" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false" class="navbar-toggle collapsed"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="http://echarts.ba [...]
+    // Incase adblock block log.js
+    ecLog = function () {};
+}
+
+function updateCheckbox() {
+    $('#charts input, #components input, #coords input').each(function () {
+        $(this).attr('checked', $(this).parent().hasClass('checked'));
+    });
+}
+
+$('#charts li, #components li, #coords li').click(function () {
+    $(this).toggleClass('checked');
+
+    updateCheckbox();
+});
+
+updateCheckbox();
+
+// Build
+$("#build").click(function () {
+    var charts = [];
+    $('#charts .checked input').each(function () {
+        charts.push($(this).attr('name'));
+    });
+
+    var components = [];
+    $('#coords .checked input').each(function () {
+        components.push($(this).attr('name'));
+    });
+    $('#components .checked input').each(function () {
+        components.push($(this).attr('name'));
+    });
+
+    var parameters = 'charts=' + charts.join(',') + '&components=' + components.join(',');
+
+    if (!$('#compress').prop('checked')) {
+        parameters += '&source=true';
+    }
+    if ($('#vml').prop('checked')) {
+        parameters += '&vml=true';
+    }
+    if ($('#svg').prop('checked')) {
+        parameters += '&svg=true';
+    }
+    if ($('#api').prop('checked')) {
+        parameters += '&api=true';
+    }
+
+    parameters += '&version=4'
+        + '&versionCode=4.1.0.rc2';
+
+    var email = $('#email').val();
+    var log = parameters;
+    if (email) {
+        log += '&email=' + email;
+    }
+    ecLog({
+        'page': 'builder',
+        'version': '4.1.0.rc2',
+        'build-parameters-3': log
+    });
+
+    window.open('builder/echarts.html?' + parameters);
+});</script><script type="text/javascript">var _hmt = _hmt || [];
+(function() {
+var hm = document.createElement("script");
+hm.src = "//hm.baidu.com/hm.js?4bad1df23f079e0d12bdbef5e65b072f";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(hm, s);
+})();</script></html>
\ No newline at end of file
diff --git a/builder/build.js b/builder/build.js
new file mode 100644
index 0000000..f0022fb
--- /dev/null
+++ b/builder/build.js
@@ -0,0 +1,272 @@
+/* global BUILD_CONFIG, UglifyJS, ActiveXObject */
+define(function (require) {
+
+    // var mangleString = require('./mangleString');
+    var saveAs = require('./lib/FileSaver');
+    var rollup = require('rollup');
+
+    var TOP_MODULE_NAME = 'topModuleInRequireES';
+
+    var $log = document.getElementById('log');
+
+    var baseURL = dir(location.pathname);
+    var suffix = BUILD_CONFIG.version === 3 ? '3' : '';
+    var pathsConfig = {
+        'echarts/src': './src/echarts' + suffix,
+        'zrender/src': './src/zrender' + suffix
+    };
+    var urlArgs = '__v__=' + (+new Date());
+
+    var topCode = [
+        'import "echarts/src/config";',
+        'export * from "echarts/src/echarts";'
+    ];
+
+    if (BUILD_CONFIG.api) {
+        topCode.push('export * from "echarts/src/export";');
+    }
+
+    // Including charts
+    (BUILD_CONFIG.charts || '').split(',').forEach(function (chart) {
+        chart && topCode.push('import "echarts/src/chart/' + chart + '";');
+    });
+
+    if (topCode.indexOf('echarts/src/chart/scatter') >= 0) {
+        topCode.push('import "echarts/src/chart/effectScatter"');
+    }
+
+    // Including components
+    (BUILD_CONFIG.components || '').split(',').forEach(function (component) {
+        component && topCode.push('import "echarts/src/component/' + component + '";');
+    });
+
+    if (BUILD_CONFIG.vml) {
+        topCode.push('import "zrender/src/vml/vml";');
+    }
+    if (BUILD_CONFIG.svg) {
+        topCode.push('import "zrender/src/svg/svg";');
+    }
+
+    // Always require log and time axis
+    topCode.push(
+        'import "echarts/src/scale/Time";',
+        'import "echarts/src/scale/Log";'
+    );
+
+    // Loading scripts and build
+    rollup.rollup({
+        input: TOP_MODULE_NAME,
+        legacy: true,
+        plugins: [{
+            resolveId: function (importee, importor) {
+                if (importee === TOP_MODULE_NAME) {
+                    return importee;
+                }
+                // console.log('resolveid', importee, importor);
+                return getAbsolutePath(
+                    importee,
+                    importor !== TOP_MODULE_NAME ? importor : null
+                );
+            },
+            load: function (path) {
+                if (path === TOP_MODULE_NAME) {
+                    return topCode.join('\n');
+                }
+                return ajax(location.origin + path)
+                    .then(function (content) {
+                        builderLog('Loaded module: "' + path + '"');
+                        return content;
+                    });
+            }
+        }]
+    }).then(function (bundle) {
+        return bundle.generate({
+            name: 'echarts',
+            format: 'umd',
+            legacy: true
+        });
+    }).then(function (result) {
+        var code = result.code;
+
+        if (!BUILD_CONFIG.source) {
+            builderLog('<br />Compressing code...');
+            // code = mangleString(code);
+            // Otherwise uglify will throw error.
+            code = code.replace(/\t/g, '    ');
+            code = jsCompress(code);
+        }
+
+        download(code);
+
+        builderLog('<br />Completed');
+
+        document.getElementById('tip').innerHTML = 'OK';
+    });
+
+    function download(code) {
+        try {
+            var blob = new Blob([code], {
+                type: 'text/plain;charset=utf8'
+            });
+
+            // var URL = window.URL || window.webkitURL;
+            // var scriptUrl = URL.createObjectURL(blob);
+
+            // URL.revokeObjectURL(blob);
+
+            // window.open(scriptUrl);
+            // return;
+
+            var fileName = ['echarts'];
+            if (BUILD_CONFIG.amd) {
+                fileName.push('amd');
+            }
+            if (!BUILD_CONFIG.source) {
+                fileName.push('min');
+            }
+            fileName.push('js');
+
+            saveAs(blob, fileName.join('.'));
+        }
+        catch (e) {
+            console.error(e);
+            window.open('data:text/plain;charset=utf-8,' + encodeURIComponent(code));
+        }
+    }
+
+    function builderLog(msg) {
+        $log.innerHTML += msg + '<br />';
+        $log.scrollTop = $log.scrollHeight;
+    }
+
+    function jsCompress(source) {
+        var ast = UglifyJS.parse(source);
+        /* jshint camelcase: false */
+        // compressor needs figure_out_scope too
+        ast.figure_out_scope();
+        ast = ast.transform(UglifyJS.Compressor());
+
+        // need to figure out scope again so mangler works optimally
+        ast.figure_out_scope();
+        ast.compute_char_frequency();
+        ast.mangle_names();
+
+        return ast.print_to_string();
+    }
+
+    // Get absolute path. `basePath` can be omitted if moduleId is absolute.
+    function getAbsolutePath(moduleId, basePath) {
+        moduleId = addExt(moduleId);
+
+        for (var path in pathsConfig) {
+            if (pathsConfig.hasOwnProperty(path)) {
+                if (moduleId.indexOf(path) === 0) {
+                    moduleId = moduleId.replace(path, pathsConfig[path]);
+                    return resolve(baseURL, moduleId);
+                }
+            }
+        }
+
+        if (basePath) {
+            moduleId = resolve(dir(basePath), moduleId);
+        }
+
+        if (moduleId.charAt(0) !== '/') {
+            throw new Error('"' + moduleId + '" can not be found.');
+        }
+
+        return moduleId;
+    }
+
+    function addExt(moduleId) {
+        if (moduleId.split('/').pop().indexOf('.') < 0) {
+            moduleId += '.js';
+        }
+        return moduleId;
+    }
+
+    function ajax(toUrl) {
+        toUrl += '?' + urlArgs;
+
+        return new Promise(function (promiseResolve, promiseReject) {
+            var xhr = window.XMLHttpRequest
+                ? new XMLHttpRequest()
+                : new ActiveXObject('Microsoft.XMLHTTP');
+
+            xhr.open('GET', toUrl, true);
+
+            xhr.onreadystatechange = function () {
+                if (xhr.readyState === 4) {
+                    (xhr.status >= 200 && xhr.status < 300)
+                        ? promiseResolve(xhr.responseText)
+                        : promiseReject({
+                            status: xhr.status,
+                            content: xhr.responseText
+                        });
+                    xhr.onreadystatechange = new Function();
+                    xhr = null;
+                }
+            };
+
+            xhr.send(null);
+        });
+    }
+
+    // Nodejs `path.resolve`.
+    function resolve() {
+        var resolvedPath = '';
+        var resolvedAbsolute;
+
+        for (var i = arguments.length - 1; i >= 0 && !resolvedAbsolute; i--) {
+            var path = arguments[i];
+            if (path) {
+                resolvedPath = path + '/' + resolvedPath;
+                resolvedAbsolute = path[0] === '/';
+            }
+        }
+
+        if (!resolvedAbsolute) {
+            throw new Error('At least one absolute path should be input.');
+        }
+
+        // Normalize the path
+        resolvedPath = normalizePathArray(resolvedPath.split('/'), false).join('/');
+
+        return '/' + resolvedPath;
+    }
+
+    // resolves . and .. elements in a path array with directory names there
+    // must be no slashes or device names (c:\) in the array
+    // (so also no leading and trailing slashes - it does not distinguish
+    // relative and absolute paths)
+    function normalizePathArray(parts, allowAboveRoot) {
+        var res = [];
+        for (var i = 0; i < parts.length; i++) {
+            var p = parts[i];
+
+            // ignore empty parts
+            if (!p || p === '.') {
+                continue;
+            }
+
+            if (p === '..') {
+                if (res.length && res[res.length - 1] !== '..') {
+                    res.pop();
+                } else if (allowAboveRoot) {
+                    res.push('..');
+                }
+            } else {
+                res.push(p);
+            }
+        }
+
+        return res;
+    }
+
+    function dir(path) {
+        if (path) {
+            return path.charAt(path.length - 1) === '/' ? path : resolve(path, '..');
+        }
+    }
+
+});
\ No newline at end of file
diff --git a/builder/chunk/amd.js b/builder/chunk/amd.js
new file mode 100644
index 0000000..807744b
--- /dev/null
+++ b/builder/chunk/amd.js
@@ -0,0 +1,127 @@
+var require, define;
+(function () {
+    var mods = {};
+
+    define = function (id, deps, factory) {
+        mods[id] = {
+            id: id,
+            deps: deps,
+            factory: factory,
+            defined: 0,
+            exports: {},
+            require: createRequire(id)
+        };
+    };
+
+    require = createRequire('');
+
+    function normalize(id, baseId) {
+        if (!baseId) {
+            return id;
+        }
+
+        if (id.indexOf('.') === 0) {
+            var basePath = baseId.split('/');
+            var namePath = id.split('/');
+            var baseLen = basePath.length - 1;
+            var nameLen = namePath.length;
+            var cutBaseTerms = 0;
+            var cutNameTerms = 0;
+
+            pathLoop: for (var i = 0; i < nameLen; i++) {
+                switch (namePath[i]) {
+                    case '..':
+                        if (cutBaseTerms < baseLen) {
+                            cutBaseTerms++;
+                            cutNameTerms++;
+                        }
+                        else {
+                            break pathLoop;
+                        }
+                        break;
+                    case '.':
+                        cutNameTerms++;
+                        break;
+                    default:
+                        break pathLoop;
+                }
+            }
+
+            basePath.length = baseLen - cutBaseTerms;
+            namePath = namePath.slice(cutNameTerms);
+
+            return basePath.concat(namePath).join('/');
+        }
+
+        return id;
+    }
+
+    function createRequire(baseId) {
+        var cacheMods = {};
+
+        function localRequire(id, callback) {
+            if (typeof id === 'string') {
+                var exports = cacheMods[id];
+                if (!exports) {
+                    exports = getModExports(normalize(id, baseId));
+                    cacheMods[id] = exports;
+                }
+
+                return exports;
+            }
+            else if (id instanceof Array) {
+                callback = callback || function () {};
+                callback.apply(this, getModsExports(id, callback, baseId));
+            }
+        };
+
+        return localRequire;
+    }
+
+    function getModsExports(ids, factory, baseId) {
+        var es = [];
+        var mod = mods[baseId];
+
+        for (var i = 0, l = Math.min(ids.length, factory.length); i < l; i++) {
+            var id = normalize(ids[i], baseId);
+            var arg;
+            switch (id) {
+                case 'require':
+                    arg = (mod && mod.require) || require;
+                    break;
+                case 'exports':
+                    arg = mod.exports;
+                    break;
+                case 'module':
+                    arg = mod;
+                    break;
+                default:
+                    arg = getModExports(id);
+            }
+            es.push(arg);
+        }
+
+        return es;
+    }
+
+    function getModExports(id) {
+        var mod = mods[id];
+        if (!mod) {
+            throw new Error('No ' + id);
+        }
+
+        if (!mod.defined) {
+            var factory = mod.factory;
+            var factoryReturn = factory.apply(
+                this,
+                getModsExports(mod.deps || [], factory, id)
+            );
+            if (typeof factoryReturn !== 'undefined') {
+                mod.exports = factoryReturn;
+            }
+            mod.defined = 1;
+        }
+
+        return mod.exports;
+    }
+}());
diff --git a/builder/chunk/end-3.js b/builder/chunk/end-3.js
new file mode 100644
index 0000000..a07bdda
--- /dev/null
+++ b/builder/chunk/end-3.js
@@ -0,0 +1,19 @@
+var echarts = require('echarts');
+
+echarts.graphic = require('echarts/util/graphic');
+echarts.number = require('echarts/util/number');
+echarts.format = require('echarts/util/format');
+
+/** for: ${charts} as ${chart} */
+require('${chart}');
+/** /for */
+/** for: ${components} as ${component} */
+require('${component}');
+/** /for */
+
+/** if: ${vml} */
+require('zrender/vml/vml');
+/** /if */
+
+return echarts;
+}));
\ No newline at end of file
diff --git a/builder/chunk/end.js b/builder/chunk/end.js
new file mode 100644
index 0000000..5e5ef51
--- /dev/null
+++ b/builder/chunk/end.js
@@ -0,0 +1,35 @@
+
+var zrender = require('zrender');
+zrender.tool = {
+    color: require('zrender/tool/color'),
+    math: require('zrender/tool/math'),
+    util: require('zrender/tool/util'),
+    vector: require('zrender/tool/vector'),
+    area: require('zrender/tool/area'),
+    event: require('zrender/tool/event')
+}
+
+zrender.animation = {
+    Animation: require('zrender/animation/Animation'),
+    Cip: require('zrender/animation/Clip'),
+    easing: require('zrender/animation/easing')
+}
+var echarts = require('echarts');
+echarts.config = require('echarts/config');
+
+/** if: ${hasMap} */
+echarts.util = {
+    mapData: {
+        params: require('echarts/util/mapData/params')
+    }
+}
+/** /if */
+/** for: ${charts} as ${chart} */
+require("${chart}");
+/** /for */
+_global['echarts'] = echarts;
+_global['zrender'] = zrender;
+
+return echarts;
+
+})(window);
diff --git a/builder/chunk/start-3.js b/builder/chunk/start-3.js
new file mode 100644
index 0000000..41790ef
--- /dev/null
+++ b/builder/chunk/start-3.js
@@ -0,0 +1,14 @@
+(function (root, factory) {
+    if (typeof define === 'function' && define.amd) {
+        // AMD. Register as an anonymous module.
+        define([], factory);
+    } else if (typeof module === 'object' && module.exports) {
+        // Node. Does not work with strict CommonJS, but
+        // only CommonJS-like environments that support module.exports,
+        // like Node.
+        module.exports = factory();
+    } else {
+        // Browser globals (root is window)
+        root.echarts = factory();
+    }
+}(this, function () {
\ No newline at end of file
diff --git a/builder/chunk/start.js b/builder/chunk/start.js
new file mode 100644
index 0000000..0a3049b
--- /dev/null
+++ b/builder/chunk/start.js
@@ -0,0 +1 @@
+(function(_global){
diff --git a/builder/echarts.html b/builder/echarts.html
new file mode 100644
index 0000000..2e75fb5
--- /dev/null
+++ b/builder/echarts.html
@@ -0,0 +1,70 @@
+<!Doctype html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <script src="lib/esl.js"></script>
+    <script src="lib/uglify.js"></script>
+    <script src="lib/escodegen.js"></script>
+
+    <style type="text/css">
+        body {
+            margin: 0;
+            text-align: center;
+        }
+        #log {
+            height: 500px;
+            overflow-y: scroll;
+
+            width: 600px;
+            text-align: left;
+            margin: 0 auto;
+
+            line-height: 18px;
+        }
+    </style>
+</head>
+<body>
+
+    <h1 id="tip">
+        Building ....
+    </h1>
+    <div id="log"></div>
+
+    <script>
+
+        var search = window.location.search;
+
+        var BUILD_CONFIG = {};
+        if (search) {
+            search = search.slice(search.indexOf('?') + 1);
+            var params = search.split('&');
+            for (var i = 0; i < params.length; i++) {
+                var keyValue = params[i].split('=');
+                var key = decodeURIComponent(keyValue[0]);
+                var value = decodeURIComponent(keyValue[1]);
+                BUILD_CONFIG[key.toLowerCase()] = parseURIValue(value);
+            }
+        }
+
+        BUILD_CONFIG.version = +BUILD_CONFIG.version || 2;
+
+        var postfix = BUILD_CONFIG.dev ? '-dev' : '';
+
+        require.config({
+            paths: {
+                'rollup': 'lib/rollup.browser',
+                'esprima': 'lib/esprima',
+                'estraverse': 'lib/estraverse'
+            },
+            urlArgs: 'v=4.1.0.rc2'
+        });
+
+        require(['build']);
+
+        function parseURIValue(value) { // for XSS
+            return value.replace(/[^0-9a-zA-Z-_,]/g, '');
+        }
+
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/builder/lib/FileSaver.js b/builder/lib/FileSaver.js
new file mode 100644
index 0000000..406e6d2
--- /dev/null
+++ b/builder/lib/FileSaver.js
@@ -0,0 +1,248 @@
+/* FileSaver.js
+ * A saveAs() FileSaver implementation.
+ * 2015-03-04
+ *
+ * By Eli Grey, http://eligrey.com
+ * License: X11/MIT
+ *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
+ */
+
+/*global self */
+/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
+
+/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
+
+var saveAs = saveAs
+  // IE 10+ (native saveAs)
+  || (typeof navigator !== "undefined" &&
+      navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
+  // Everyone else
+  || (function(view) {
+    "use strict";
+    // IE <10 is explicitly unsupported
+    if (typeof navigator !== "undefined" &&
+        /MSIE [1-9]\./.test(navigator.userAgent)) {
+        return;
+    }
+    var
+          doc = view.document
+          // only get URL when necessary in case Blob.js hasn't overridden it yet
+        , get_URL = function() {
+            return view.URL || view.webkitURL || view;
+        }
+        , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
+        , can_use_save_link = "download" in save_link
+        , click = function(node) {
+            var event = doc.createEvent("MouseEvents");
+            event.initMouseEvent(
+                "click", true, false, view, 0, 0, 0, 0, 0
+                , false, false, false, false, 0, null
+            );
+            node.dispatchEvent(event);
+        }
+        , webkit_req_fs = view.webkitRequestFileSystem
+        , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
+        , throw_outside = function(ex) {
+            (view.setImmediate || view.setTimeout)(function() {
+                throw ex;
+            }, 0);
+        }
+        , force_saveable_type = "application/octet-stream"
+        , fs_min_size = 0
+        // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
+        // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
+        // for the reasoning behind the timeout and revocation flow
+        , arbitrary_revoke_timeout = 500 // in ms
+        , revoke = function(file) {
+            var revoker = function() {
+                if (typeof file === "string") { // file is an object URL
+                    get_URL().revokeObjectURL(file);
+                } else { // file is a File
+                    file.remove();
+                }
+            };
+            if (view.chrome) {
+                revoker();
+            } else {
+                setTimeout(revoker, arbitrary_revoke_timeout);
+            }
+        }
+        , dispatch = function(filesaver, event_types, event) {
+            event_types = [].concat(event_types);
+            var i = event_types.length;
+            while (i--) {
+                var listener = filesaver["on" + event_types[i]];
+                if (typeof listener === "function") {
+                    try {
+                        listener.call(filesaver, event || filesaver);
+                    } catch (ex) {
+                        throw_outside(ex);
+                    }
+                }
+            }
+        }
+        , FileSaver = function(blob, name) {
+            // First try a.download, then web filesystem, then object URLs
+            var
+                  filesaver = this
+                , type = blob.type
+                , blob_changed = false
+                , object_url
+                , target_view
+                , dispatch_all = function() {
+                    dispatch(filesaver, "writestart progress write writeend".split(" "));
+                }
+                // on any filesys errors revert to saving with object URLs
+                , fs_error = function() {
+                    // don't create more object URLs than needed
+                    if (blob_changed || !object_url) {
+                        object_url = get_URL().createObjectURL(blob);
+                    }
+                    if (target_view) {
+                        target_view.location.href = object_url;
+                    } else {
+                        var new_tab = view.open(object_url, "_blank");
+                        if (new_tab == undefined && typeof safari !== "undefined") {
+                            //Apple do not allow window.open, see http://bit.ly/1kZffRI
+                            view.location.href = object_url
+                        }
+                    }
+                    filesaver.readyState = filesaver.DONE;
+                    dispatch_all();
+                    revoke(object_url);
+                }
+                , abortable = function(func) {
+                    return function() {
+                        if (filesaver.readyState !== filesaver.DONE) {
+                            return func.apply(this, arguments);
+                        }
+                    };
+                }
+                , create_if_not_found = {create: true, exclusive: false}
+                , slice
+            ;
+            filesaver.readyState = filesaver.INIT;
+            if (!name) {
+                name = "download";
+            }
+            if (can_use_save_link) {
+                object_url = get_URL().createObjectURL(blob);
+                save_link.href = object_url;
+                save_link.download = name;
+                click(save_link);
+                filesaver.readyState = filesaver.DONE;
+                dispatch_all();
+                revoke(object_url);
+                return;
+            }
+            // prepend BOM for UTF-8 XML and text/plain types
+            if (/^\s*(?:text\/(?:plain|xml)|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
+                blob = new Blob(["\ufeff", blob], {type: blob.type});
+            }
+            // Object and web filesystem URLs have a problem saving in Google Chrome when
+            // viewed in a tab, so I force save with application/octet-stream
+            // http://code.google.com/p/chromium/issues/detail?id=91158
+            // Update: Google errantly closed 91158, I submitted it again:
+            // https://code.google.com/p/chromium/issues/detail?id=389642
+            if (view.chrome && type && type !== force_saveable_type) {
+                slice = blob.slice || blob.webkitSlice;
+                blob = slice.call(blob, 0, blob.size, force_saveable_type);
+                blob_changed = true;
+            }
+            // Since I can't be sure that the guessed media type will trigger a download
+            // in WebKit, I append .download to the filename.
+            // https://bugs.webkit.org/show_bug.cgi?id=65440
+            if (webkit_req_fs && name !== "download") {
+                name += ".download";
+            }
+            if (type === force_saveable_type || webkit_req_fs) {
+                target_view = view;
+            }
+            if (!req_fs) {
+                fs_error();
+                return;
+            }
+            fs_min_size += blob.size;
+            req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
+                fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
+                    var save = function() {
+                        dir.getFile(name, create_if_not_found, abortable(function(file) {
+                            file.createWriter(abortable(function(writer) {
+                                writer.onwriteend = function(event) {
+                                    target_view.location.href = file.toURL();
+                                    filesaver.readyState = filesaver.DONE;
+                                    dispatch(filesaver, "writeend", event);
+                                    revoke(file);
+                                };
+                                writer.onerror = function() {
+                                    var error = writer.error;
+                                    if (error.code !== error.ABORT_ERR) {
+                                        fs_error();
+                                    }
+                                };
+                                "writestart progress write abort".split(" ").forEach(function(event) {
+                                    writer["on" + event] = filesaver["on" + event];
+                                });
+                                writer.write(blob);
+                                filesaver.abort = function() {
+                                    writer.abort();
+                                    filesaver.readyState = filesaver.DONE;
+                                };
+                                filesaver.readyState = filesaver.WRITING;
+                            }), fs_error);
+                        }), fs_error);
+                    };
+                    dir.getFile(name, {create: false}, abortable(function(file) {
+                        // delete file if it already exists
+                        file.remove();
+                        save();
+                    }), abortable(function(ex) {
+                        if (ex.code === ex.NOT_FOUND_ERR) {
+                            save();
+                        } else {
+                            fs_error();
+                        }
+                    }));
+                }), fs_error);
+            }), fs_error);
+        }
+        , FS_proto = FileSaver.prototype
+        , saveAs = function(blob, name) {
+            return new FileSaver(blob, name);
+        }
+    ;
+    FS_proto.abort = function() {
+        var filesaver = this;
+        filesaver.readyState = filesaver.DONE;
+        dispatch(filesaver, "abort");
+    };
+    FS_proto.readyState = FS_proto.INIT = 0;
+    FS_proto.WRITING = 1;
+    FS_proto.DONE = 2;
+
+    FS_proto.error =
+    FS_proto.onwritestart =
+    FS_proto.onprogress =
+    FS_proto.onwrite =
+    FS_proto.onabort =
+    FS_proto.onerror =
+    FS_proto.onwriteend =
+        null;
+
+    return saveAs;
+}(
+       typeof self !== "undefined" && self
+    || typeof window !== "undefined" && window
+    || this.content
+));
+// `self` is undefined in Firefox for Android content script context
+// while `this` is nsIContentFrameMessageManager
+// with an attribute `content` that corresponds to the window
+
+if (typeof module !== "undefined" && module.exports) {
+  module.exports.saveAs = saveAs;
+} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
+  define([], function() {
+    return saveAs;
+  });
+}
\ No newline at end of file
diff --git a/builder/lib/escodegen.js b/builder/lib/escodegen.js
new file mode 100644
index 0000000..f1185ae
--- /dev/null
+++ b/builder/lib/escodegen.js
@@ -0,0 +1,2965 @@
+// Generated by browserify
+(function(){var require = function (file, cwd) {
+    var resolved = require.resolve(file, cwd || '/');
+    var mod = require.modules[resolved];
+    if (!mod) throw new Error(
+        'Failed to resolve module ' + file + ', tried ' + resolved
+    );
+    var cached = require.cache[resolved];
+    var res = cached ? cached.exports : mod();
+    return res;
+};
+
+require.paths = [];
+require.modules = {};
+require.cache = {};
+require.extensions = [".js",".coffee",".json"];
+
+require._core = {
+    'assert': true,
+    'events': true,
+    'fs': true,
+    'path': true,
+    'vm': true
+};
+
+require.resolve = (function () {
+    return function (x, cwd) {
+        if (!cwd) cwd = '/';
+
+        if (require._core[x]) return x;
+        var path = require.modules.path();
+        cwd = path.resolve('/', cwd);
+        var y = cwd || '/';
+
+        if (x.match(/^(?:\.\.?\/|\/)/)) {
+            var m = loadAsFileSync(path.resolve(y, x))
+                || loadAsDirectorySync(path.resolve(y, x));
+            if (m) return m;
+        }
+
+        var n = loadNodeModulesSync(x, y);
+        if (n) return n;
+
+        throw new Error("Cannot find module '" + x + "'");
+
+        function loadAsFileSync (x) {
+            x = path.normalize(x);
+            if (require.modules[x]) {
+                return x;
+            }
+
+            for (var i = 0; i < require.extensions.length; i++) {
+                var ext = require.extensions[i];
+                if (require.modules[x + ext]) return x + ext;
+            }
+        }
+
+        function loadAsDirectorySync (x) {
+            x = x.replace(/\/+$/, '');
+            var pkgfile = path.normalize(x + '/package.json');
+            if (require.modules[pkgfile]) {
+                var pkg = require.modules[pkgfile]();
+                var b = pkg.browserify;
+                if (typeof b === 'object' && b.main) {
+                    var m = loadAsFileSync(path.resolve(x, b.main));
+                    if (m) return m;
+                }
+                else if (typeof b === 'string') {
+                    var m = loadAsFileSync(path.resolve(x, b));
+                    if (m) return m;
+                }
+                else if (pkg.main) {
+                    var m = loadAsFileSync(path.resolve(x, pkg.main));
+                    if (m) return m;
+                }
+            }
+
+            return loadAsFileSync(x + '/index');
+        }
+
+        function loadNodeModulesSync (x, start) {
+            var dirs = nodeModulesPathsSync(start);
+            for (var i = 0; i < dirs.length; i++) {
+                var dir = dirs[i];
+                var m = loadAsFileSync(dir + '/' + x);
+                if (m) return m;
+                var n = loadAsDirectorySync(dir + '/' + x);
+                if (n) return n;
+            }
+
+            var m = loadAsFileSync(x);
+            if (m) return m;
+        }
+
+        function nodeModulesPathsSync (start) {
+            var parts;
+            if (start === '/') parts = [ '' ];
+            else parts = path.normalize(start).split('/');
+
+            var dirs = [];
+            for (var i = parts.length - 1; i >= 0; i--) {
+                if (parts[i] === 'node_modules') continue;
+                var dir = parts.slice(0, i + 1).join('/') + '/node_modules';
+                dirs.push(dir);
+            }
+
+            return dirs;
+        }
+    };
+})();
+
+require.alias = function (from, to) {
+    var path = require.modules.path();
+    var res = null;
+    try {
+        res = require.resolve(from + '/package.json', '/');
+    }
+    catch (err) {
+        res = require.resolve(from, '/');
+    }
+    var basedir = path.dirname(res);
+
+    var keys = (Object.keys || function (obj) {
+        var res = [];
+        for (var key in obj) res.push(key);
+        return res;
+    })(require.modules);
+
+    for (var i = 0; i < keys.length; i++) {
+        var key = keys[i];
+        if (key.slice(0, basedir.length + 1) === basedir + '/') {
+            var f = key.slice(basedir.length);
+            require.modules[to + f] = require.modules[basedir + f];
+        }
+        else if (key === basedir) {
+            require.modules[to] = require.modules[basedir];
+        }
+    }
+};
+
+(function () {
+    var process = {};
+    var global = typeof window !== 'undefined' ? window : {};
+    var definedProcess = false;
+
+    require.define = function (filename, fn) {
+        if (!definedProcess && require.modules.__browserify_process) {
+            process = require.modules.__browserify_process();
+            definedProcess = true;
+        }
+
+        var dirname = require._core[filename]
+            ? ''
+            : require.modules.path().dirname(filename)
+        ;
+
+        var require_ = function (file) {
+            var requiredModule = require(file, dirname);
+            var cached = require.cache[require.resolve(file, dirname)];
+
+            if (cached && cached.parent === null) {
+                cached.parent = module_;
+            }
+
+            return requiredModule;
+        };
+        require_.resolve = function (name) {
+            return require.resolve(name, dirname);
+        };
+        require_.modules = require.modules;
+        require_.define = require.define;
+        require_.cache = require.cache;
+        var module_ = {
+            id : filename,
+            filename: filename,
+            exports : {},
+            loaded : false,
+            parent: null
+        };
+
+        require.modules[filename] = function () {
+            require.cache[filename] = module_;
+            fn.call(
+                module_.exports,
+                require_,
+                module_,
+                module_.exports,
+                dirname,
+                filename,
+                process,
+                global
+            );
+            module_.loaded = true;
+            return module_.exports;
+        };
+    };
+})();
+
+
+require.define("path",function(require,module,exports,__dirname,__filename,process,global){function filter (xs, fn) {
+    var res = [];
+    for (var i = 0; i < xs.length; i++) {
+        if (fn(xs[i], i, xs)) res.push(xs[i]);
+    }
+    return res;
+}
+
+// resolves . and .. elements in a path array with directory names there
+// must be no slashes, empty elements, or device names (c:\) in the array
+// (so also no leading and trailing slashes - it does not distinguish
+// relative and absolute paths)
+function normalizeArray(parts, allowAboveRoot) {
+  // if the path tries to go above the root, `up` ends up > 0
+  var up = 0;
+  for (var i = parts.length; i >= 0; i--) {
+    var last = parts[i];
+    if (last == '.') {
+      parts.splice(i, 1);
+    } else if (last === '..') {
+      parts.splice(i, 1);
+      up++;
+    } else if (up) {
+      parts.splice(i, 1);
+      up--;
+    }
+  }
+
+  // if the path is allowed to go above the root, restore leading ..s
+  if (allowAboveRoot) {
+    for (; up--; up) {
+      parts.unshift('..');
+    }
+  }
+
+  return parts;
+}
+
+// Regex to split a filename into [*, dir, basename, ext]
+// posix version
+var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/;
+
+// path.resolve([from ...], to)
+// posix version
+exports.resolve = function() {
+var resolvedPath = '',
+    resolvedAbsolute = false;
+
+for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {
+  var path = (i >= 0)
+      ? arguments[i]
+      : process.cwd();
+
+  // Skip empty and invalid entries
+  if (typeof path !== 'string' || !path) {
+    continue;
+  }
+
+  resolvedPath = path + '/' + resolvedPath;
+  resolvedAbsolute = path.charAt(0) === '/';
+}
+
+// At this point the path should be resolved to a full absolute path, but
+// handle relative paths to be safe (might happen when process.cwd() fails)
+
+// Normalize the path
+resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
+    return !!p;
+  }), !resolvedAbsolute).join('/');
+
+  return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+};
+
+// path.normalize(path)
+// posix version
+exports.normalize = function(path) {
+var isAbsolute = path.charAt(0) === '/',
+    trailingSlash = path.slice(-1) === '/';
+
+// Normalize the path
+path = normalizeArray(filter(path.split('/'), function(p) {
+    return !!p;
+  }), !isAbsolute).join('/');
+
+  if (!path && !isAbsolute) {
+    path = '.';
+  }
+  if (path && trailingSlash) {
+    path += '/';
+  }
+
+  return (isAbsolute ? '/' : '') + path;
+};
+
+
+// posix version
+exports.join = function() {
+  var paths = Array.prototype.slice.call(arguments, 0);
+  return exports.normalize(filter(paths, function(p, index) {
+    return p && typeof p === 'string';
+  }).join('/'));
+};
+
+
+exports.dirname = function(path) {
+  var dir = splitPathRe.exec(path)[1] || '';
+  var isWindows = false;
+  if (!dir) {
+    // No dirname
+    return '.';
+  } else if (dir.length === 1 ||
+      (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) {
+    // It is just a slash or a drive letter with a slash
+    return dir;
+  } else {
+    // It is a full dirname, strip trailing slash
+    return dir.substring(0, dir.length - 1);
+  }
+};
+
+
+exports.basename = function(path, ext) {
+  var f = splitPathRe.exec(path)[2] || '';
+  // TODO: make this comparison case-insensitive on windows?
+  if (ext && f.substr(-1 * ext.length) === ext) {
+    f = f.substr(0, f.length - ext.length);
+  }
+  return f;
+};
+
+
+exports.extname = function(path) {
+  return splitPathRe.exec(path)[3] || '';
+};
+
+exports.relative = function(from, to) {
+  from = exports.resolve(from).substr(1);
+  to = exports.resolve(to).substr(1);
+
+  function trim(arr) {
+    var start = 0;
+    for (; start < arr.length; start++) {
+      if (arr[start] !== '') break;
+    }
+
+    var end = arr.length - 1;
+    for (; end >= 0; end--) {
+      if (arr[end] !== '') break;
+    }
+
+    if (start > end) return [];
+    return arr.slice(start, end - start + 1);
+  }
+
+  var fromParts = trim(from.split('/'));
+  var toParts = trim(to.split('/'));
+
+  var length = Math.min(fromParts.length, toParts.length);
+  var samePartsLength = length;
+  for (var i = 0; i < length; i++) {
+    if (fromParts[i] !== toParts[i]) {
+      samePartsLength = i;
+      break;
+    }
+  }
+
+  var outputParts = [];
+  for (var i = samePartsLength; i < fromParts.length; i++) {
+    outputParts.push('..');
+  }
+
+  outputParts = outputParts.concat(toParts.slice(samePartsLength));
+
+  return outputParts.join('/');
+};
+
+});
+
+require.define("__browserify_process",function(require,module,exports,__dirname,__filename,process,global){var process = module.exports = {};
+
+process.nextTick = (function () {
+    var canSetImmediate = typeof window !== 'undefined'
+        && window.setImmediate;
+    var canPost = typeof window !== 'undefined'
+        && window.postMessage && window.addEventListener
+    ;
+
+    if (canSetImmediate) {
+        return function (f) { return window.setImmediate(f) };
+    }
+
+    if (canPost) {
+        var queue = [];
+        window.addEventListener('message', function (ev) {
+            if (ev.source === window && ev.data === 'browserify-tick') {
+                ev.stopPropagation();
+                if (queue.length > 0) {
+                    var fn = queue.shift();
+                    fn();
+                }
+            }
+        }, true);
+
+        return function nextTick(fn) {
+            queue.push(fn);
+            window.postMessage('browserify-tick', '*');
+        };
+    }
+
+    return function nextTick(fn) {
+        setTimeout(fn, 0);
+    };
+})();
+
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+
+process.binding = function (name) {
+    if (name === 'evals') return (require)('vm')
+    else throw new Error('No such module. (Possibly not yet loaded)')
+};
+
+(function () {
+    var cwd = '/';
+    var path;
+    process.cwd = function () { return cwd };
+    process.chdir = function (dir) {
+        if (!path) path = require('path');
+        cwd = path.resolve(dir, cwd);
+    };
+})();
+
+});
+
+require.define("/package.json",function(require,module,exports,__dirname,__filename,process,global){module.exports = {"main":"escodegen.js"}
+});
+
+require.define("/escodegen.js",function(require,module,exports,__dirname,__filename,process,global){/*
+  Copyright (C) 2012 Michael Ficarra <es...@michael.ficarra.me>
+  Copyright (C) 2012 Robert Gust-Bardon <do...@robert.gust-bardon.org>
+  Copyright (C) 2012 John Freeman <jf...@gmail.com>
+  Copyright (C) 2011-2012 Ariya Hidayat <ar...@gmail.com>
+  Copyright (C) 2012 Mathias Bynens <ma...@qiwi.be>
+  Copyright (C) 2012 Joost-Wim Boekesteijn <jo...@boekesteijn.nl>
+  Copyright (C) 2012 Kris Kowal <kr...@cixar.com>
+  Copyright (C) 2012 Yusuke Suzuki <ut...@gmail.com>
+  Copyright (C) 2012 Arpad Borsos <ar...@googlemail.com>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*jslint bitwise:true */
+/*global escodegen:true, exports:true, generateStatement:true, generateExpression:true, generateFunctionBody:true, process:true, require:true, define:true*/
+(function () {
+    'use strict';
+
+    var Syntax,
+        Precedence,
+        BinaryPrecedence,
+        Regex,
+        VisitorKeys,
+        VisitorOption,
+        SourceNode,
+        isArray,
+        base,
+        indent,
+        json,
+        renumber,
+        hexadecimal,
+        quotes,
+        escapeless,
+        newline,
+        space,
+        parentheses,
+        semicolons,
+        safeConcatenation,
+        directive,
+        extra,
+        parse,
+        sourceMap,
+        traverse;
+
+    traverse = require('estraverse').traverse;
+
+    Syntax = {
+        AssignmentExpression: 'AssignmentExpression',
+        ArrayExpression: 'ArrayExpression',
+        ArrayPattern: 'ArrayPattern',
+        BlockStatement: 'BlockStatement',
+        BinaryExpression: 'BinaryExpression',
+        BreakStatement: 'BreakStatement',
+        CallExpression: 'CallExpression',
+        CatchClause: 'CatchClause',
+        ComprehensionBlock: 'ComprehensionBlock',
+        ComprehensionExpression: 'ComprehensionExpression',
+        ConditionalExpression: 'ConditionalExpression',
+        ContinueStatement: 'ContinueStatement',
+        DirectiveStatement: 'DirectiveStatement',
+        DoWhileStatement: 'DoWhileStatement',
+        DebuggerStatement: 'DebuggerStatement',
+        EmptyStatement: 'EmptyStatement',
+        ExpressionStatement: 'ExpressionStatement',
+        ForStatement: 'ForStatement',
+        ForInStatement: 'ForInStatement',
+        FunctionDeclaration: 'FunctionDeclaration',
+        FunctionExpression: 'FunctionExpression',
+        Identifier: 'Identifier',
+        IfStatement: 'IfStatement',
+        Literal: 'Literal',
+        LabeledStatement: 'LabeledStatement',
+        LogicalExpression: 'LogicalExpression',
+        MemberExpression: 'MemberExpression',
+        NewExpression: 'NewExpression',
+        ObjectExpression: 'ObjectExpression',
+        ObjectPattern: 'ObjectPattern',
+        Program: 'Program',
+        Property: 'Property',
+        ReturnStatement: 'ReturnStatement',
+        SequenceExpression: 'SequenceExpression',
+        SwitchStatement: 'SwitchStatement',
+        SwitchCase: 'SwitchCase',
+        ThisExpression: 'ThisExpression',
+        ThrowStatement: 'ThrowStatement',
+        TryStatement: 'TryStatement',
+        UnaryExpression: 'UnaryExpression',
+        UpdateExpression: 'UpdateExpression',
+        VariableDeclaration: 'VariableDeclaration',
+        VariableDeclarator: 'VariableDeclarator',
+        WhileStatement: 'WhileStatement',
+        WithStatement: 'WithStatement',
+        YieldExpression: 'YieldExpression',
+
+    };
+
+    Precedence = {
+        Sequence: 0,
+        Assignment: 1,
+        Conditional: 2,
+        LogicalOR: 3,
+        LogicalAND: 4,
+        BitwiseOR: 5,
+        BitwiseXOR: 6,
+        BitwiseAND: 7,
+        Equality: 8,
+        Relational: 9,
+        BitwiseSHIFT: 10,
+        Additive: 11,
+        Multiplicative: 12,
+        Unary: 13,
+        Postfix: 14,
+        Call: 15,
+        New: 16,
+        Member: 17,
+        Primary: 18
+    };
+
+    BinaryPrecedence = {
+        '||': Precedence.LogicalOR,
+        '&&': Precedence.LogicalAND,
+        '|': Precedence.BitwiseOR,
+        '^': Precedence.BitwiseXOR,
+        '&': Precedence.BitwiseAND,
+        '==': Precedence.Equality,
+        '!=': Precedence.Equality,
+        '===': Precedence.Equality,
+        '!==': Precedence.Equality,
+        'is': Precedence.Equality,
+        'isnt': Precedence.Equality,
+        '<': Precedence.Relational,
+        '>': Precedence.Relational,
+        '<=': Precedence.Relational,
+        '>=': Precedence.Relational,
+        'in': Precedence.Relational,
+        'instanceof': Precedence.Relational,
+        '<<': Precedence.BitwiseSHIFT,
+        '>>': Precedence.BitwiseSHIFT,
+        '>>>': Precedence.BitwiseSHIFT,
+        '+': Precedence.Additive,
+        '-': Precedence.Additive,
+        '*': Precedence.Multiplicative,
+        '%': Precedence.Multiplicative,
+        '/': Precedence.Multiplicative
+    };
+
+    Regex = {
+        NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u08 [...]
+    };
+
+    function getDefaultOptions() {
+        // default options
+        return {
+            indent: null,
+            base: null,
+            parse: null,
+            comment: false,
+            format: {
+                indent: {
+                    style: '    ',
+                    base: 0,
+                    adjustMultilineComment: false
+                },
+                json: false,
+                renumber: false,
+                hexadecimal: false,
+                quotes: 'single',
+                escapeless: false,
+                compact: false,
+                parentheses: true,
+                semicolons: true,
+                safeConcatenation: false
+            },
+            moz: {
+                starlessGenerator: false,
+                parenthesizedComprehensionBlock: false
+            },
+            sourceMap: null,
+            sourceMapRoot: null,
+            sourceMapWithCode: false,
+            directive: false,
+            verbatim: null
+        };
+    }
+
+    function stringToArray(str) {
+        var length = str.length,
+            result = [],
+            i;
+        for (i = 0; i < length; i += 1) {
+            result[i] = str.charAt(i);
+        }
+        return result;
+    }
+
+    function stringRepeat(str, num) {
+        var result = '';
+
+        for (num |= 0; num > 0; num >>>= 1, str += str) {
+            if (num & 1) {
+                result += str;
+            }
+        }
+
+        return result;
+    }
+
+    isArray = Array.isArray;
+    if (!isArray) {
+        isArray = function isArray(array) {
+            return Object.prototype.toString.call(array) === '[object Array]';
+        };
+    }
+
+    // Fallback for the non SourceMap environment
+    function SourceNodeMock(line, column, filename, chunk) {
+        var result = [];
+
+        function flatten(input) {
+            var i, iz;
+            if (isArray(input)) {
+                for (i = 0, iz = input.length; i < iz; ++i) {
+                    flatten(input[i]);
+                }
+            } else if (input instanceof SourceNodeMock) {
+                result.push(input);
+            } else if (typeof input === 'string' && input) {
+                result.push(input);
+            }
+        }
+
+        flatten(chunk);
+        this.children = result;
+    }
+
+    SourceNodeMock.prototype.toString = function toString() {
+        var res = '', i, iz, node;
+        for (i = 0, iz = this.children.length; i < iz; ++i) {
+            node = this.children[i];
+            if (node instanceof SourceNodeMock) {
+                res += node.toString();
+            } else {
+                res += node;
+            }
+        }
+        return res;
+    };
+
+    SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) {
+        var last = this.children[this.children.length - 1];
+        if (last instanceof SourceNodeMock) {
+            last.replaceRight(pattern, replacement);
+        } else if (typeof last === 'string') {
+            this.children[this.children.length - 1] = last.replace(pattern, replacement);
+        } else {
+            this.children.push(''.replace(pattern, replacement));
+        }
+        return this;
+    };
+
+    SourceNodeMock.prototype.join = function join(sep) {
+        var i, iz, result;
+        result = [];
+        iz = this.children.length;
+        if (iz > 0) {
+            for (i = 0, iz -= 1; i < iz; ++i) {
+                result.push(this.children[i], sep);
+            }
+            result.push(this.children[iz]);
+            this.children = result;
+        }
+        return this;
+    };
+
+    function hasLineTerminator(str) {
+        return /[\r\n]/g.test(str);
+    }
+
+    function endsWithLineTerminator(str) {
+        var ch = str.charAt(str.length - 1);
+        return ch === '\r' || ch === '\n';
+    }
+
+    function shallowCopy(obj) {
+        var ret = {}, key;
+        for (key in obj) {
+            if (obj.hasOwnProperty(key)) {
+                ret[key] = obj[key];
+            }
+        }
+        return ret;
+    }
+
+    function deepCopy(obj) {
+        var ret = {}, key, val;
+        for (key in obj) {
+            if (obj.hasOwnProperty(key)) {
+                val = obj[key];
+                if (typeof val === 'object' && val !== null) {
+                    ret[key] = deepCopy(val);
+                } else {
+                    ret[key] = val;
+                }
+            }
+        }
+        return ret;
+    }
+
+    function updateDeeply(target, override) {
+        var key, val;
+
+        function isHashObject(target) {
+            return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp);
+        }
+
+        for (key in override) {
+            if (override.hasOwnProperty(key)) {
+                val = override[key];
+                if (isHashObject(val)) {
+                    if (isHashObject(target[key])) {
+                        updateDeeply(target[key], val);
+                    } else {
+                        target[key] = updateDeeply({}, val);
+                    }
+                } else {
+                    target[key] = val;
+                }
+            }
+        }
+        return target;
+    }
+
+    function generateNumber(value) {
+        var result, point, temp, exponent, pos;
+
+        if (value !== value) {
+            throw new Error('Numeric literal whose value is NaN');
+        }
+        if (value < 0 || (value === 0 && 1 / value < 0)) {
+            throw new Error('Numeric literal whose value is negative');
+        }
+
+        if (value === 1 / 0) {
+            return json ? 'null' : renumber ? '1e400' : '1e+400';
+        }
+
+        result = '' + value;
+        if (!renumber || result.length < 3) {
+            return result;
+        }
+
+        point = result.indexOf('.');
+        if (!json && result.charAt(0) === '0' && point === 1) {
+            point = 0;
+            result = result.slice(1);
+        }
+        temp = result;
+        result = result.replace('e+', 'e');
+        exponent = 0;
+        if ((pos = temp.indexOf('e')) > 0) {
+            exponent = +temp.slice(pos + 1);
+            temp = temp.slice(0, pos);
+        }
+        if (point >= 0) {
+            exponent -= temp.length - point - 1;
+            temp = +(temp.slice(0, point) + temp.slice(point + 1)) + '';
+        }
+        pos = 0;
+        while (temp.charAt(temp.length + pos - 1) === '0') {
+            pos -= 1;
+        }
+        if (pos !== 0) {
+            exponent -= pos;
+            temp = temp.slice(0, pos);
+        }
+        if (exponent !== 0) {
+            temp += 'e' + exponent;
+        }
+        if ((temp.length < result.length ||
+                    (hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) &&
+                +temp === value) {
+            result = temp;
+        }
+
+        return result;
+    }
+
+    function escapeAllowedCharacter(ch, next) {
+        var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\';
+
+        switch (ch) {
+        case '\b':
+            result += 'b';
+            break;
+        case '\f':
+            result += 'f';
+            break;
+        case '\t':
+            result += 't';
+            break;
+        default:
+            if (json || code > 0xff) {
+                result += 'u' + '0000'.slice(hex.length) + hex;
+            } else if (ch === '\u0000' && '0123456789'.indexOf(next) < 0) {
+                result += '0';
+            } else if (ch === '\v') {
+                result += 'v';
+            } else {
+                result += 'x' + '00'.slice(hex.length) + hex;
+            }
+            break;
+        }
+
+        return result;
+    }
+
+    function escapeDisallowedCharacter(ch) {
+        var result = '\\';
+        switch (ch) {
+        case '\\':
+            result += '\\';
+            break;
+        case '\n':
+            result += 'n';
+            break;
+        case '\r':
+            result += 'r';
+            break;
+        case '\u2028':
+            result += 'u2028';
+            break;
+        case '\u2029':
+            result += 'u2029';
+            break;
+        default:
+            throw new Error('Incorrectly classified character');
+        }
+
+        return result;
+    }
+
+    function escapeDirective(str) {
+        var i, iz, ch, single, buf, quote;
+
+        buf = str;
+        if (typeof buf[0] === 'undefined') {
+            buf = stringToArray(buf);
+        }
+
+        quote = quotes === 'double' ? '"' : '\'';
+        for (i = 0, iz = buf.length; i < iz; i += 1) {
+            ch = buf[i];
+            if (ch === '\'') {
+                quote = '"';
+                break;
+            } else if (ch === '"') {
+                quote = '\'';
+                break;
+            } else if (ch === '\\') {
+                i += 1;
+            }
+        }
+
+        return quote + str + quote;
+    }
+
+    function escapeString(str) {
+        var result = '', i, len, ch, next, singleQuotes = 0, doubleQuotes = 0, single;
+
+        if (typeof str[0] === 'undefined') {
+            str = stringToArray(str);
+        }
+
+        for (i = 0, len = str.length; i < len; i += 1) {
+            ch = str[i];
+            if (ch === '\'') {
+                singleQuotes += 1;
+            } else if (ch === '"') {
+                doubleQuotes += 1;
+            } else if (ch === '/' && json) {
+                result += '\\';
+            } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) {
+                result += escapeDisallowedCharacter(ch);
+                continue;
+            } else if ((json && ch < ' ') || !(json || escapeless || (ch >= ' ' && ch <= '~'))) {
+                result += escapeAllowedCharacter(ch, str[i + 1]);
+                continue;
+            }
+            result += ch;
+        }
+
+        single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes));
+        str = result;
+        result = single ? '\'' : '"';
+
+        if (typeof str[0] === 'undefined') {
+            str = stringToArray(str);
+        }
+
+        for (i = 0, len = str.length; i < len; i += 1) {
+            ch = str[i];
+            if ((ch === '\'' && single) || (ch === '"' && !single)) {
+                result += '\\';
+            }
+            result += ch;
+        }
+
+        return result + (single ? '\'' : '"');
+    }
+
+    function isWhiteSpace(ch) {
+        return '\t\v\f \xa0'.indexOf(ch) >= 0 || (ch.charCodeAt(0) >= 0x1680 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0);
+    }
+
+    function isLineTerminator(ch) {
+        return '\n\r\u2028\u2029'.indexOf(ch) >= 0;
+    }
+
+    function isIdentifierPart(ch) {
+        return (ch === '$') || (ch === '_') || (ch === '\\') ||
+            (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+            ((ch >= '0') && (ch <= '9')) ||
+            ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
+    }
+
+    function toSourceNode(generated, node) {
+        if (node == null) {
+            if (generated instanceof SourceNode) {
+                return generated;
+            } else {
+                node = {};
+            }
+        }
+        if (node.loc == null) {
+            return new SourceNode(null, null, sourceMap, generated);
+        }
+        return new SourceNode(node.loc.start.line, node.loc.start.column, (sourceMap === true ? node.loc.source || null : sourceMap), generated);
+    }
+
+    function join(left, right) {
+        var leftSource = toSourceNode(left).toString(),
+            rightSource = toSourceNode(right).toString(),
+            leftChar = leftSource.charAt(leftSource.length - 1),
+            rightChar = rightSource.charAt(0);
+
+        if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) {
+            return [left, ' ', right];
+        } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) {
+            return [left, right];
+        }
+        return [left, space, right];
+    }
+
+    function addIndent(stmt) {
+        return [base, stmt];
+    }
+
+    function withIndent(fn) {
+        var previousBase, result;
+        previousBase = base;
+        base += indent;
+        result = fn.call(this, base);
+        base = previousBase;
+        return result;
+    }
+
+    function calculateSpaces(str) {
+        var i;
+        for (i = str.length - 1; i >= 0; i -= 1) {
+            if (isLineTerminator(str.charAt(i))) {
+                break;
+            }
+        }
+        return (str.length - 1) - i;
+    }
+
+    function adjustMultilineComment(value, specialBase) {
+        var array, i, len, line, j, ch, spaces, previousBase;
+
+        array = value.split(/\r\n|[\r\n]/);
+        spaces = Number.MAX_VALUE;
+
+        // first line doesn't have indentation
+        for (i = 1, len = array.length; i < len; i += 1) {
+            line = array[i];
+            j = 0;
+            while (j < line.length && isWhiteSpace(line[j])) {
+                j += 1;
+            }
+            if (spaces > j) {
+                spaces = j;
+            }
+        }
+
+        if (typeof specialBase !== 'undefined') {
+            // pattern like
+            // {
+            //   var t = 20;  /*
+            //                 * this is comment
+            //                 */
+            // }
+            previousBase = base;
+            if (array[1][spaces] === '*') {
+                specialBase += ' ';
+            }
+            base = specialBase;
+        } else {
+            if (spaces & 1) {
+                // /*
+                //  *
+                //  */
+                // If spaces are odd number, above pattern is considered.
+                // We waste 1 space.
+                spaces -= 1;
+            }
+            previousBase = base;
+        }
+
+        for (i = 1, len = array.length; i < len; i += 1) {
+            array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join('');
+        }
+
+        base = previousBase;
+
+        return array.join('\n');
+    }
+
+    function generateComment(comment, specialBase) {
+        if (comment.type === 'Line') {
+            if (endsWithLineTerminator(comment.value)) {
+                return '//' + comment.value;
+            } else {
+                // Always use LineTerminator
+                return '//' + comment.value + '\n';
+            }
+        }
+        if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
+            return adjustMultilineComment('/*' + comment.value + '*/', specialBase);
+        }
+        return '/*' + comment.value + '*/';
+    }
+
+    function addCommentsToStatement(stmt, result) {
+        var i, len, comment, save, node, tailingToStatement, specialBase, fragment;
+
+        if (stmt.leadingComments && stmt.leadingComments.length > 0) {
+            save = result;
+
+            comment = stmt.leadingComments[0];
+            result = [];
+            if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) {
+                result.push('\n');
+            }
+            result.push(generateComment(comment));
+            if (!endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push('\n');
+            }
+
+            for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) {
+                comment = stmt.leadingComments[i];
+                fragment = [generateComment(comment)];
+                if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                    fragment.push('\n');
+                }
+                result.push(addIndent(fragment));
+            }
+
+            result.push(addIndent(save));
+        }
+
+        if (stmt.trailingComments) {
+            tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString());
+            specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([base, result, indent]).toString()));
+            for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) {
+                comment = stmt.trailingComments[i];
+                if (tailingToStatement) {
+                    // We assume target like following script
+                    //
+                    // var t = 20;  /**
+                    //               * This is comment of t
+                    //               */
+                    if (i === 0) {
+                        // first case
+                        result = [result, indent];
+                    } else {
+                        result = [result, specialBase];
+                    }
+                    result.push(generateComment(comment, specialBase));
+                } else {
+                    result = [result, addIndent(generateComment(comment))];
+                }
+                if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                    result = [result, '\n'];
+                }
+            }
+        }
+
+        return result;
+    }
+
+    function parenthesize(text, current, should) {
+        if (current < should) {
+            return ['(', text, ')'];
+        }
+        return text;
+    }
+
+    function maybeBlock(stmt, semicolonOptional, functionBody) {
+        var result, noLeadingComment;
+
+        noLeadingComment = !extra.comment || !stmt.leadingComments;
+
+        if (stmt.type === Syntax.BlockStatement && noLeadingComment) {
+            return [space, generateStatement(stmt, { functionBody: functionBody })];
+        }
+
+        if (stmt.type === Syntax.EmptyStatement && noLeadingComment) {
+            return ';';
+        }
+
+        withIndent(function () {
+            result = [newline, addIndent(generateStatement(stmt, { semicolonOptional: semicolonOptional, functionBody: functionBody }))];
+        });
+
+        return result;
+    }
+
+    function maybeBlockSuffix(stmt, result) {
+        var ends = endsWithLineTerminator(toSourceNode(result).toString());
+        if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) {
+            return [result, space];
+        }
+        if (ends) {
+            return [result, base];
+        }
+        return [result, newline, base];
+    }
+
+    function generateVerbatim(expr, option) {
+        var i, result;
+        result = expr[extra.verbatim].split(/\r\n|\n/);
+        for (i = 1; i < result.length; i++) {
+            result[i] = newline + base + result[i];
+        }
+
+        result = parenthesize(result, Precedence.Sequence, option.precedence);
+        return toSourceNode(result, expr);
+    }
+
+    function generateFunctionBody(node) {
+        var result, i, len, expr;
+        result = ['('];
+        for (i = 0, len = node.params.length; i < len; i += 1) {
+            result.push(node.params[i].name);
+            if (i + 1 < len) {
+                result.push(',' + space);
+            }
+        }
+        result.push(')');
+
+        if (node.expression) {
+            result.push(space);
+            expr = generateExpression(node.body, {
+                precedence: Precedence.Assignment,
+                allowIn: true,
+                allowCall: true
+            });
+            if (expr.toString().charAt(0) === '{') {
+                expr = ['(', expr, ')'];
+            }
+            result.push(expr);
+        } else {
+            result.push(maybeBlock(node.body, false, true));
+        }
+        return result;
+    }
+
+    function generateExpression(expr, option) {
+        var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, rightSource, allowIn, allowCall, allowUnparenthesizedNew, property, key, value;
+
+        precedence = option.precedence;
+        allowIn = option.allowIn;
+        allowCall = option.allowCall;
+        type = expr.type || option.type;
+
+        if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) {
+            return generateVerbatim(expr, option);
+        }
+
+        switch (type) {
+        case Syntax.SequenceExpression:
+            result = [];
+            allowIn |= (Precedence.Sequence < precedence);
+            for (i = 0, len = expr.expressions.length; i < len; i += 1) {
+                result.push(generateExpression(expr.expressions[i], {
+                    precedence: Precedence.Assignment,
+                    allowIn: allowIn,
+                    allowCall: true
+                }));
+                if (i + 1 < len) {
+                    result.push(',' + space);
+                }
+            }
+            result = parenthesize(result, Precedence.Sequence, precedence);
+            break;
+
+        case Syntax.AssignmentExpression:
+            allowIn |= (Precedence.Assignment < precedence);
+            result = parenthesize(
+                [
+                    generateExpression(expr.left, {
+                        precedence: Precedence.Call,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }),
+                    space + expr.operator + space,
+                    generateExpression(expr.right, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    })
+                ],
+                Precedence.Assignment,
+                precedence
+            );
+            break;
+
+        case Syntax.ConditionalExpression:
+            allowIn |= (Precedence.Conditional < precedence);
+            result = parenthesize(
+                [
+                    generateExpression(expr.test, {
+                        precedence: Precedence.LogicalOR,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }),
+                    space + '?' + space,
+                    generateExpression(expr.consequent, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }),
+                    space + ':' + space,
+                    generateExpression(expr.alternate, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    })
+                ],
+                Precedence.Conditional,
+                precedence
+            );
+            break;
+
+        case Syntax.LogicalExpression:
+        case Syntax.BinaryExpression:
+            currentPrecedence = BinaryPrecedence[expr.operator];
+
+            allowIn |= (currentPrecedence < precedence);
+
+            result = join(
+                generateExpression(expr.left, {
+                    precedence: currentPrecedence,
+                    allowIn: allowIn,
+                    allowCall: true
+                }),
+                expr.operator
+            );
+
+            fragment = generateExpression(expr.right, {
+                precedence: currentPrecedence + 1,
+                allowIn: allowIn,
+                allowCall: true
+            });
+
+            if (expr.operator === '/' && fragment.toString().charAt(0) === '/') {
+                // If '/' concats with '/', it is interpreted as comment start
+                result.push(' ', fragment);
+            } else {
+                result = join(result, fragment);
+            }
+
+            if (expr.operator === 'in' && !allowIn) {
+                result = ['(', result, ')'];
+            } else {
+                result = parenthesize(result, currentPrecedence, precedence);
+            }
+
+            break;
+
+        case Syntax.CallExpression:
+            result = [generateExpression(expr.callee, {
+                precedence: Precedence.Call,
+                allowIn: true,
+                allowCall: true,
+                allowUnparenthesizedNew: false
+            })];
+
+            result.push('(');
+            for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
+                result.push(generateExpression(expr['arguments'][i], {
+                    precedence: Precedence.Assignment,
+                    allowIn: true,
+                    allowCall: true
+                }));
+                if (i + 1 < len) {
+                    result.push(',' + space);
+                }
+            }
+            result.push(')');
+
+            if (!allowCall) {
+                result = ['(', result, ')'];
+            } else {
+                result = parenthesize(result, Precedence.Call, precedence);
+            }
+            break;
+
+        case Syntax.NewExpression:
+            len = expr['arguments'].length;
+            allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew;
+
+            result = join(
+                'new',
+                generateExpression(expr.callee, {
+                    precedence: Precedence.New,
+                    allowIn: true,
+                    allowCall: false,
+                    allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0
+                })
+            );
+
+            if (!allowUnparenthesizedNew || parentheses || len > 0) {
+                result.push('(');
+                for (i = 0; i < len; i += 1) {
+                    result.push(generateExpression(expr['arguments'][i], {
+                        precedence: Precedence.Assignment,
+                        allowIn: true,
+                        allowCall: true
+                    }));
+                    if (i + 1 < len) {
+                        result.push(',' + space);
+                    }
+                }
+                result.push(')');
+            }
+
+            result = parenthesize(result, Precedence.New, precedence);
+            break;
+
+        case Syntax.MemberExpression:
+            result = [generateExpression(expr.object, {
+                precedence: Precedence.Call,
+                allowIn: true,
+                allowCall: allowCall,
+                allowUnparenthesizedNew: false
+            })];
+
+            if (expr.computed) {
+                result.push('[', generateExpression(expr.property, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: allowCall
+                }), ']');
+            } else {
+                if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
+                    if (result.indexOf('.') < 0) {
+                        if (!/[eExX]/.test(result) && !(result.length >= 2 && result[0] === '0')) {
+                            result.push('.');
+                        }
+                    }
+                }
+                result.push('.' + expr.property.name);
+            }
+
+            result = parenthesize(result, Precedence.Member, precedence);
+            break;
+
+        case Syntax.UnaryExpression:
+            fragment = generateExpression(expr.argument, {
+                precedence: Precedence.Unary,
+                allowIn: true,
+                allowCall: true
+            });
+
+            if (space === '') {
+                result = join(expr.operator, fragment);
+            } else {
+                result = [expr.operator];
+                if (expr.operator.length > 2) {
+                    // delete, void, typeof
+                    // get `typeof []`, not `typeof[]`
+                    result = join(result, fragment);
+                } else {
+                    // Prevent inserting spaces between operator and argument if it is unnecessary
+                    // like, `!cond`
+                    leftSource = toSourceNode(result).toString();
+                    leftChar = leftSource.charAt(leftSource.length - 1);
+                    rightChar = fragment.toString().charAt(0);
+
+                    if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) {
+                        result.push(' ', fragment);
+                    } else {
+                        result.push(fragment);
+                    }
+                }
+            }
+            result = parenthesize(result, Precedence.Unary, precedence);
+            break;
+
+        case Syntax.YieldExpression:
+            if (expr.delegate) {
+                result = 'yield*';
+            } else {
+                result = 'yield';
+            }
+            if (expr.argument) {
+                result = join(
+                    result,
+                    generateExpression(expr.argument, {
+                        precedence: Precedence.Assignment,
+                        allowIn: true,
+                        allowCall: true
+                    })
+                );
+            }
+            break;
+
+        case Syntax.UpdateExpression:
+            if (expr.prefix) {
+                result = parenthesize(
+                    [
+                        expr.operator,
+                        generateExpression(expr.argument, {
+                            precedence: Precedence.Unary,
+                            allowIn: true,
+                            allowCall: true
+                        })
+                    ],
+                    Precedence.Unary,
+                    precedence
+                );
+            } else {
+                result = parenthesize(
+                    [
+                        generateExpression(expr.argument, {
+                            precedence: Precedence.Postfix,
+                            allowIn: true,
+                            allowCall: true
+                        }),
+                        expr.operator
+                    ],
+                    Precedence.Postfix,
+                    precedence
+                );
+            }
+            break;
+
+        case Syntax.FunctionExpression:
+            result = 'function';
+            if (expr.id) {
+                result += ' ' + expr.id.name;
+            } else {
+                result += space;
+            }
+
+            result = [result, generateFunctionBody(expr)];
+            break;
+
+        case Syntax.ArrayPattern:
+        case Syntax.ArrayExpression:
+            if (!expr.elements.length) {
+                result = '[]';
+                break;
+            }
+            multiline = expr.elements.length > 1;
+            result = ['[', multiline ? newline : ''];
+            withIndent(function (indent) {
+                for (i = 0, len = expr.elements.length; i < len; i += 1) {
+                    if (!expr.elements[i]) {
+                        if (multiline) {
+                            result.push(indent);
+                        }
+                        if (i + 1 === len) {
+                            result.push(',');
+                        }
+                    } else {
+                        result.push(multiline ? indent : '', generateExpression(expr.elements[i], {
+                            precedence: Precedence.Assignment,
+                            allowIn: true,
+                            allowCall: true
+                        }));
+                    }
+                    if (i + 1 < len) {
+                        result.push(',' + (multiline ? newline : space));
+                    }
+                }
+            });
+            if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push(newline);
+            }
+            result.push(multiline ? base : '', ']');
+            break;
+
+        case Syntax.Property:
+            if (expr.kind === 'get' || expr.kind === 'set') {
+                result = [
+                    expr.kind + ' ',
+                    generateExpression(expr.key, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    generateFunctionBody(expr.value)
+                ];
+            } else {
+                if (expr.shorthand) {
+                    result = generateExpression(expr.key, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    });
+                } else if (expr.method) {
+                    result = [];
+                    if (expr.value.generator) {
+                        result.push('*');
+                    }
+                    result.push(generateExpression(expr.key, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }), generateFunctionBody(expr.value));
+                } else {
+                    result = [
+                        generateExpression(expr.key, {
+                            precedence: Precedence.Sequence,
+                            allowIn: true,
+                            allowCall: true
+                        }),
+                        ':' + space,
+                        generateExpression(expr.value, {
+                            precedence: Precedence.Assignment,
+                            allowIn: true,
+                            allowCall: true
+                        })
+                    ];
+                }
+            }
+            break;
+
+        case Syntax.ObjectExpression:
+            if (!expr.properties.length) {
+                result = '{}';
+                break;
+            }
+            multiline = expr.properties.length > 1;
+
+            withIndent(function (indent) {
+                fragment = generateExpression(expr.properties[0], {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true,
+                    type: Syntax.Property
+                });
+            });
+
+            if (!multiline) {
+                // issues 4
+                // Do not transform from
+                //   dejavu.Class.declare({
+                //       method2: function () {}
+                //   });
+                // to
+                //   dejavu.Class.declare({method2: function () {
+                //       }});
+                if (!hasLineTerminator(toSourceNode(fragment).toString())) {
+                    result = [ '{', space, fragment, space, '}' ];
+                    break;
+                }
+            }
+
+            withIndent(function (indent) {
+                result = [ '{', newline, indent, fragment ];
+
+                if (multiline) {
+                    result.push(',' + newline);
+                    for (i = 1, len = expr.properties.length; i < len; i += 1) {
+                        result.push(indent, generateExpression(expr.properties[i], {
+                            precedence: Precedence.Sequence,
+                            allowIn: true,
+                            allowCall: true,
+                            type: Syntax.Property
+                        }));
+                        if (i + 1 < len) {
+                            result.push(',' + newline);
+                        }
+                    }
+                }
+            });
+
+            if (!endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push(newline);
+            }
+            result.push(base, '}');
+            break;
+
+        case Syntax.ObjectPattern:
+            if (!expr.properties.length) {
+                result = '{}';
+                break;
+            }
+
+            multiline = false;
+            if (expr.properties.length === 1) {
+                property = expr.properties[0];
+                if (property.value.type !== Syntax.Identifier) {
+                    multiline = true;
+                }
+            } else {
+                for (i = 0, len = expr.properties.length; i < len; i += 1) {
+                    property = expr.properties[i];
+                    if (!property.shorthand) {
+                        multiline = true;
+                        break;
+                    }
+                }
+            }
+            result = ['{', multiline ? newline : '' ];
+
+            withIndent(function (indent) {
+                for (i = 0, len = expr.properties.length; i < len; i += 1) {
+                    result.push(multiline ? indent : '', generateExpression(expr.properties[i], {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }));
+                    if (i + 1 < len) {
+                        result.push(',' + (multiline ? newline : space));
+                    }
+                }
+            });
+
+            if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                result.push(newline);
+            }
+            result.push(multiline ? base : '', '}');
+            break;
+
+        case Syntax.ThisExpression:
+            result = 'this';
+            break;
+
+        case Syntax.Identifier:
+            result = expr.name;
+            break;
+
+        case Syntax.Literal:
+            if (expr.hasOwnProperty('raw') && parse) {
+                try {
+                    raw = parse(expr.raw).body[0].expression;
+                    if (raw.type === Syntax.Literal) {
+                        if (raw.value === expr.value) {
+                            result = expr.raw;
+                            break;
+                        }
+                    }
+                } catch (e) {
+                    // not use raw property
+                }
+            }
+
+            if (expr.value === null) {
+                result = 'null';
+                break;
+            }
+
+            if (typeof expr.value === 'string') {
+                result = escapeString(expr.value);
+                break;
+            }
+
+            if (typeof expr.value === 'number') {
+                result = generateNumber(expr.value);
+                break;
+            }
+
+            result = expr.value.toString();
+            break;
+
+        case Syntax.ComprehensionExpression:
+            result = [
+                '[',
+                generateExpression(expr.body, {
+                    precedence: Precedence.Assignment,
+                    allowIn: true,
+                    allowCall: true
+                })
+            ];
+
+            if (expr.blocks) {
+                for (i = 0, len = expr.blocks.length; i < len; i += 1) {
+                    fragment = generateExpression(expr.blocks[i], {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    });
+                    result = join(result, fragment);
+                }
+            }
+
+            if (expr.filter) {
+                result = join(result, 'if' + space);
+                fragment = generateExpression(expr.filter, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                });
+                if (extra.moz.parenthesizedComprehensionBlock) {
+                    result = join(result, [ '(', fragment, ')' ]);
+                } else {
+                    result = join(result, fragment);
+                }
+            }
+            result.push(']');
+            break;
+
+        case Syntax.ComprehensionBlock:
+            if (expr.left.type === Syntax.VariableDeclaration) {
+                fragment = [
+                    expr.left.kind + ' ',
+                    generateStatement(expr.left.declarations[0], {
+                        allowIn: false
+                    })
+                ];
+            } else {
+                fragment = generateExpression(expr.left, {
+                    precedence: Precedence.Call,
+                    allowIn: true,
+                    allowCall: true
+                });
+            }
+
+            fragment = join(fragment, expr.of ? 'of' : 'in');
+            fragment = join(fragment, generateExpression(expr.right, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            }));
+
+            if (extra.moz.parenthesizedComprehensionBlock) {
+                result = [ 'for' + space + '(', fragment, ')' ];
+            } else {
+                result = join('for' + space, fragment);
+            }
+            break;
+
+        default:
+            throw new Error('Unknown expression type: ' + expr.type);
+        }
+
+        return toSourceNode(result, expr);
+    }
+
+    function generateStatement(stmt, option) {
+        var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon;
+
+        allowIn = true;
+        semicolon = ';';
+        functionBody = false;
+        directiveContext = false;
+        if (option) {
+            allowIn = option.allowIn === undefined || option.allowIn;
+            if (!semicolons && option.semicolonOptional === true) {
+                semicolon = '';
+            }
+            functionBody = option.functionBody;
+            directiveContext = option.directiveContext;
+        }
+
+        switch (stmt.type) {
+        case Syntax.BlockStatement:
+            result = ['{', newline];
+
+            withIndent(function () {
+                for (i = 0, len = stmt.body.length; i < len; i += 1) {
+                    fragment = addIndent(generateStatement(stmt.body[i], {
+                        semicolonOptional: i === len - 1,
+                        directiveContext: functionBody
+                    }));
+                    result.push(fragment);
+                    if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                        result.push(newline);
+                    }
+                }
+            });
+
+            result.push(addIndent('}'));
+            break;
+
+        case Syntax.BreakStatement:
+            if (stmt.label) {
+                result = 'break ' + stmt.label.name + semicolon;
+            } else {
+                result = 'break' + semicolon;
+            }
+            break;
+
+        case Syntax.ContinueStatement:
+            if (stmt.label) {
+                result = 'continue ' + stmt.label.name + semicolon;
+            } else {
+                result = 'continue' + semicolon;
+            }
+            break;
+
+        case Syntax.DirectiveStatement:
+            if (stmt.raw) {
+                result = stmt.raw + semicolon;
+            } else {
+                result = escapeDirective(stmt.directive) + semicolon;
+            }
+            break;
+
+        case Syntax.DoWhileStatement:
+            // Because `do 42 while (cond)` is Syntax Error. We need semicolon.
+            result = join('do', maybeBlock(stmt.body));
+            result = maybeBlockSuffix(stmt.body, result);
+            result = join(result, [
+                'while' + space + '(',
+                generateExpression(stmt.test, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                }),
+                ')' + semicolon
+            ]);
+            break;
+
+        case Syntax.CatchClause:
+            withIndent(function () {
+                result = [
+                    'catch' + space + '(',
+                    generateExpression(stmt.param, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')'
+                ];
+            });
+            result.push(maybeBlock(stmt.body));
+            break;
+
+        case Syntax.DebuggerStatement:
+            result = 'debugger' + semicolon;
+            break;
+
+        case Syntax.EmptyStatement:
+            result = ';';
+            break;
+
+        case Syntax.ExpressionStatement:
+            result = [generateExpression(stmt.expression, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            })];
+            // 12.4 '{', 'function' is not allowed in this position.
+            // wrap expression with parentheses
+            if (result.toString().charAt(0) === '{' || (result.toString().slice(0, 8) === 'function' && " (".indexOf(result.toString().charAt(8)) >= 0) || (directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string')) {
+                result = ['(', result, ')' + semicolon];
+            } else {
+                result.push(semicolon);
+            }
+            break;
+
+        case Syntax.VariableDeclarator:
+            if (stmt.init) {
+                result = [
+                    generateExpression(stmt.id, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    }) + space + '=' + space,
+                    generateExpression(stmt.init, {
+                        precedence: Precedence.Assignment,
+                        allowIn: allowIn,
+                        allowCall: true
+                    })
+                ];
+            } else {
+                result = stmt.id.name;
+            }
+            break;
+
+        case Syntax.VariableDeclaration:
+            result = [stmt.kind];
+            // special path for
+            // var x = function () {
+            // };
+            if (stmt.declarations.length === 1 && stmt.declarations[0].init &&
+                    stmt.declarations[0].init.type === Syntax.FunctionExpression) {
+                result.push(' ', generateStatement(stmt.declarations[0], {
+                    allowIn: allowIn
+                }));
+            } else {
+                // VariableDeclarator is typed as Statement,
+                // but joined with comma (not LineTerminator).
+                // So if comment is attached to target node, we should specialize.
+                withIndent(function () {
+                    node = stmt.declarations[0];
+                    if (extra.comment && node.leadingComments) {
+                        result.push('\n', addIndent(generateStatement(node, {
+                            allowIn: allowIn
+                        })));
+                    } else {
+                        result.push(' ', generateStatement(node, {
+                            allowIn: allowIn
+                        }));
+                    }
+
+                    for (i = 1, len = stmt.declarations.length; i < len; i += 1) {
+                        node = stmt.declarations[i];
+                        if (extra.comment && node.leadingComments) {
+                            result.push(',' + newline, addIndent(generateStatement(node, {
+                                allowIn: allowIn
+                            })));
+                        } else {
+                            result.push(',' + space, generateStatement(node, {
+                                allowIn: allowIn
+                            }));
+                        }
+                    }
+                });
+            }
+            result.push(semicolon);
+            break;
+
+        case Syntax.ThrowStatement:
+            result = [join(
+                'throw',
+                generateExpression(stmt.argument, {
+                    precedence: Precedence.Sequence,
+                    allowIn: true,
+                    allowCall: true
+                })
+            ), semicolon];
+            break;
+
+        case Syntax.TryStatement:
+            result = ['try', maybeBlock(stmt.block)];
+            result = maybeBlockSuffix(stmt.block, result);
+            for (i = 0, len = stmt.handlers.length; i < len; i += 1) {
+                result = join(result, generateStatement(stmt.handlers[i]));
+                if (stmt.finalizer || i + 1 !== len) {
+                    result = maybeBlockSuffix(stmt.handlers[i].body, result);
+                }
+            }
+            if (stmt.finalizer) {
+                result = join(result, ['finally', maybeBlock(stmt.finalizer)]);
+            }
+            break;
+
+        case Syntax.SwitchStatement:
+            withIndent(function () {
+                result = [
+                    'switch' + space + '(',
+                    generateExpression(stmt.discriminant, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')' + space + '{' + newline
+                ];
+            });
+            if (stmt.cases) {
+                for (i = 0, len = stmt.cases.length; i < len; i += 1) {
+                    fragment = addIndent(generateStatement(stmt.cases[i], {semicolonOptional: i === len - 1}));
+                    result.push(fragment);
+                    if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                        result.push(newline);
+                    }
+                }
+            }
+            result.push(addIndent('}'));
+            break;
+
+        case Syntax.SwitchCase:
+            withIndent(function () {
+                if (stmt.test) {
+                    result = [
+                        join('case', generateExpression(stmt.test, {
+                            precedence: Precedence.Sequence,
+                            allowIn: true,
+                            allowCall: true
+                        })),
+                        ':'
+                    ];
+                } else {
+                    result = ['default:'];
+                }
+
+                i = 0;
+                len = stmt.consequent.length;
+                if (len && stmt.consequent[0].type === Syntax.BlockStatement) {
+                    fragment = maybeBlock(stmt.consequent[0]);
+                    result.push(fragment);
+                    i = 1;
+                }
+
+                if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) {
+                    result.push(newline);
+                }
+
+                for (; i < len; i += 1) {
+                    fragment = addIndent(generateStatement(stmt.consequent[i], {semicolonOptional: i === len - 1 && semicolon === ''}));
+                    result.push(fragment);
+                    if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                        result.push(newline);
+                    }
+                }
+            });
+            break;
+
+        case Syntax.IfStatement:
+            withIndent(function () {
+                result = [
+                    'if' + space + '(',
+                    generateExpression(stmt.test, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')'
+                ];
+            });
+            if (stmt.alternate) {
+                result.push(maybeBlock(stmt.consequent));
+                result = maybeBlockSuffix(stmt.consequent, result);
+                if (stmt.alternate.type === Syntax.IfStatement) {
+                    result = join(result, ['else ', generateStatement(stmt.alternate, {semicolonOptional: semicolon === ''})]);
+                } else {
+                    result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === '')));
+                }
+            } else {
+                result.push(maybeBlock(stmt.consequent, semicolon === ''));
+            }
+            break;
+
+        case Syntax.ForStatement:
+            withIndent(function () {
+                result = ['for' + space + '('];
+                if (stmt.init) {
+                    if (stmt.init.type === Syntax.VariableDeclaration) {
+                        result.push(generateStatement(stmt.init, {allowIn: false}));
+                    } else {
+                        result.push(generateExpression(stmt.init, {
+                            precedence: Precedence.Sequence,
+                            allowIn: false,
+                            allowCall: true
+                        }), ';');
+                    }
+                } else {
+                    result.push(';');
+                }
+
+                if (stmt.test) {
+                    result.push(space, generateExpression(stmt.test, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }), ';');
+                } else {
+                    result.push(';');
+                }
+
+                if (stmt.update) {
+                    result.push(space, generateExpression(stmt.update, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }), ')');
+                } else {
+                    result.push(')');
+                }
+            });
+
+            result.push(maybeBlock(stmt.body, semicolon === ''));
+            break;
+
+        case Syntax.ForInStatement:
+            result = ['for' + space + '('];
+            withIndent(function () {
+                if (stmt.left.type === Syntax.VariableDeclaration) {
+                    withIndent(function () {
+                        result.push(stmt.left.kind + ' ', generateStatement(stmt.left.declarations[0], {
+                            allowIn: false
+                        }));
+                    });
+                } else {
+                    result.push(generateExpression(stmt.left, {
+                        precedence: Precedence.Call,
+                        allowIn: true,
+                        allowCall: true
+                    }));
+                }
+
+                result = join(result, 'in');
+                result = [join(
+                    result,
+                    generateExpression(stmt.right, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    })
+                ), ')'];
+            });
+            result.push(maybeBlock(stmt.body, semicolon === ''));
+            break;
+
+        case Syntax.LabeledStatement:
+            result = [stmt.label.name + ':', maybeBlock(stmt.body, semicolon === '')];
+            break;
+
+        case Syntax.Program:
+            len = stmt.body.length;
+            result = [safeConcatenation && len > 0 ? '\n' : ''];
+            for (i = 0; i < len; i += 1) {
+                fragment = addIndent(
+                    generateStatement(stmt.body[i], {
+                        semicolonOptional: !safeConcatenation && i === len - 1,
+                        directiveContext: true
+                    })
+                );
+                result.push(fragment);
+                if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) {
+                    result.push(newline);
+                }
+            }
+            break;
+
+        case Syntax.FunctionDeclaration:
+            result = [(stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function ') + stmt.id.name, generateFunctionBody(stmt)];
+            break;
+
+        case Syntax.ReturnStatement:
+            if (stmt.argument) {
+                result = [join(
+                    'return',
+                    generateExpression(stmt.argument, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    })
+                ), semicolon];
+            } else {
+                result = ['return' + semicolon];
+            }
+            break;
+
+        case Syntax.WhileStatement:
+            withIndent(function () {
+                result = [
+                    'while' + space + '(',
+                    generateExpression(stmt.test, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')'
+                ];
+            });
+            result.push(maybeBlock(stmt.body, semicolon === ''));
+            break;
+
+        case Syntax.WithStatement:
+            withIndent(function () {
+                result = [
+                    'with' + space + '(',
+                    generateExpression(stmt.object, {
+                        precedence: Precedence.Sequence,
+                        allowIn: true,
+                        allowCall: true
+                    }),
+                    ')'
+                ];
+            });
+            result.push(maybeBlock(stmt.body, semicolon === ''));
+            break;
+
+        default:
+            throw new Error('Unknown statement type: ' + stmt.type);
+        }
+
+        // Attach comments
+
+        if (extra.comment) {
+            result = addCommentsToStatement(stmt, result);
+        }
+
+        fragment = toSourceNode(result).toString();
+        if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' &&  fragment.charAt(fragment.length - 1) === '\n') {
+            result = toSourceNode(result).replaceRight(/\s+$/, '');
+        }
+
+        return toSourceNode(result, stmt);
+    }
+
+    function generate(node, options) {
+        var defaultOptions = getDefaultOptions(), result, pair;
+
+        if (options != null) {
+            // Obsolete options
+            //
+            //   `options.indent`
+            //   `options.base`
+            //
+            // Instead of them, we can use `option.format.indent`.
+            if (typeof options.indent === 'string') {
+                defaultOptions.format.indent.style = options.indent;
+            }
+            if (typeof options.base === 'number') {
+                defaultOptions.format.indent.base = options.base;
+            }
+            options = updateDeeply(defaultOptions, options);
+            indent = options.format.indent.style;
+            if (typeof options.base === 'string') {
+                base = options.base;
+            } else {
+                base = stringRepeat(indent, options.format.indent.base);
+            }
+        } else {
+            options = defaultOptions;
+            indent = options.format.indent.style;
+            base = stringRepeat(indent, options.format.indent.base);
+        }
+        json = options.format.json;
+        renumber = options.format.renumber;
+        hexadecimal = json ? false : options.format.hexadecimal;
+        quotes = json ? 'double' : options.format.quotes;
+        escapeless = options.format.escapeless;
+        if (options.format.compact) {
+            newline = space = indent = base = '';
+        } else {
+            newline = '\n';
+            space = ' ';
+        }
+        parentheses = options.format.parentheses;
+        semicolons = options.format.semicolons;
+        safeConcatenation = options.format.safeConcatenation;
+        directive = options.directive;
+        parse = json ? null : options.parse;
+        sourceMap = options.sourceMap;
+        extra = options;
+
+        if (sourceMap) {
+            if (!exports.browser) {
+                // We assume environment is node.js
+                // And prevent from including source-map by browserify
+                SourceNode = require('source-map').SourceNode;
+            } else {
+                SourceNode = global.sourceMap.SourceNode;
+            }
+        } else {
+            SourceNode = SourceNodeMock;
+        }
+
+        switch (node.type) {
+        case Syntax.BlockStatement:
+        case Syntax.BreakStatement:
+        case Syntax.CatchClause:
+        case Syntax.ContinueStatement:
+        case Syntax.DirectiveStatement:
+        case Syntax.DoWhileStatement:
+        case Syntax.DebuggerStatement:
+        case Syntax.EmptyStatement:
+        case Syntax.ExpressionStatement:
+        case Syntax.ForStatement:
+        case Syntax.ForInStatement:
+        case Syntax.FunctionDeclaration:
+        case Syntax.IfStatement:
+        case Syntax.LabeledStatement:
+        case Syntax.Program:
+        case Syntax.ReturnStatement:
+        case Syntax.SwitchStatement:
+        case Syntax.SwitchCase:
+        case Syntax.ThrowStatement:
+        case Syntax.TryStatement:
+        case Syntax.VariableDeclaration:
+        case Syntax.VariableDeclarator:
+        case Syntax.WhileStatement:
+        case Syntax.WithStatement:
+            result = generateStatement(node);
+            break;
+
+        case Syntax.AssignmentExpression:
+        case Syntax.ArrayExpression:
+        case Syntax.ArrayPattern:
+        case Syntax.BinaryExpression:
+        case Syntax.CallExpression:
+        case Syntax.ConditionalExpression:
+        case Syntax.FunctionExpression:
+        case Syntax.Identifier:
+        case Syntax.Literal:
+        case Syntax.LogicalExpression:
+        case Syntax.MemberExpression:
+        case Syntax.NewExpression:
+        case Syntax.ObjectExpression:
+        case Syntax.ObjectPattern:
+        case Syntax.Property:
+        case Syntax.SequenceExpression:
+        case Syntax.ThisExpression:
+        case Syntax.UnaryExpression:
+        case Syntax.UpdateExpression:
+        case Syntax.YieldExpression:
+
+            result = generateExpression(node, {
+                precedence: Precedence.Sequence,
+                allowIn: true,
+                allowCall: true
+            });
+            break;
+
+        default:
+            throw new Error('Unknown node type: ' + node.type);
+        }
+
+        if (!sourceMap) {
+            return result.toString();
+        }
+
+        pair = result.toStringWithSourceMap({
+            file: options.sourceMap,
+            sourceRoot: options.sourceMapRoot
+        });
+
+        if (options.sourceMapWithCode) {
+            return pair;
+        }
+        return pair.map.toString();
+    }
+
+    // simple visitor implementation
+
+    VisitorKeys = {
+        AssignmentExpression: ['left', 'right'],
+        ArrayExpression: ['elements'],
+        ArrayPattern: ['elements'],
+        BlockStatement: ['body'],
+        BinaryExpression: ['left', 'right'],
+        BreakStatement: ['label'],
+        CallExpression: ['callee', 'arguments'],
+        CatchClause: ['param', 'body'],
+        ConditionalExpression: ['test', 'consequent', 'alternate'],
+        ContinueStatement: ['label'],
+        DirectiveStatement: [],
+        DoWhileStatement: ['body', 'test'],
+        DebuggerStatement: [],
+        EmptyStatement: [],
+        ExpressionStatement: ['expression'],
+        ForStatement: ['init', 'test', 'update', 'body'],
+        ForInStatement: ['left', 'right', 'body'],
+        FunctionDeclaration: ['id', 'params', 'body'],
+        FunctionExpression: ['id', 'params', 'body'],
+        Identifier: [],
+        IfStatement: ['test', 'consequent', 'alternate'],
+        Literal: [],
+        LabeledStatement: ['label', 'body'],
+        LogicalExpression: ['left', 'right'],
+        MemberExpression: ['object', 'property'],
+        NewExpression: ['callee', 'arguments'],
+        ObjectExpression: ['properties'],
+        ObjectPattern: ['properties'],
+        Program: ['body'],
+        Property: ['key', 'value'],
+        ReturnStatement: ['argument'],
+        SequenceExpression: ['expressions'],
+        SwitchStatement: ['discriminant', 'cases'],
+        SwitchCase: ['test', 'consequent'],
+        ThisExpression: [],
+        ThrowStatement: ['argument'],
+        TryStatement: ['block', 'handlers', 'finalizer'],
+        UnaryExpression: ['argument'],
+        UpdateExpression: ['argument'],
+        VariableDeclaration: ['declarations'],
+        VariableDeclarator: ['id', 'init'],
+        WhileStatement: ['test', 'body'],
+        WithStatement: ['object', 'body'],
+        YieldExpression: ['argument']
+    };
+
+    VisitorOption = {
+        Break: 1,
+        Skip: 2
+    };
+
+    // based on LLVM libc++ upper_bound / lower_bound
+    // MIT License
+
+    function upperBound(array, func) {
+        var diff, len, i, current;
+
+        len = array.length;
+        i = 0;
+
+        while (len) {
+            diff = len >>> 1;
+            current = i + diff;
+            if (func(array[current])) {
+                len = diff;
+            } else {
+                i = current + 1;
+                len -= diff + 1;
+            }
+        }
+        return i;
+    }
+
+    function lowerBound(array, func) {
+        var diff, len, i, current;
+
+        len = array.length;
+        i = 0;
+
+        while (len) {
+            diff = len >>> 1;
+            current = i + diff;
+            if (func(array[current])) {
+                i = current + 1;
+                len -= diff + 1;
+            } else {
+                len = diff;
+            }
+        }
+        return i;
+    }
+
+    function extendCommentRange(comment, tokens) {
+        var target, token;
+
+        target = upperBound(tokens, function search(token) {
+            return token.range[0] > comment.range[0];
+        });
+
+        comment.extendedRange = [comment.range[0], comment.range[1]];
+
+        if (target !== tokens.length) {
+            comment.extendedRange[1] = tokens[target].range[0];
+        }
+
+        target -= 1;
+        if (target >= 0) {
+            if (target < tokens.length) {
+                comment.extendedRange[0] = tokens[target].range[1];
+            } else if (token.length) {
+                comment.extendedRange[1] = tokens[tokens.length - 1].range[0];
+            }
+        }
+
+        return comment;
+    }
+
+    function attachComments(tree, providedComments, tokens) {
+        // At first, we should calculate extended comment ranges.
+        var comments = [], comment, len, i;
+
+        if (!tree.range) {
+            throw new Error('attachComments needs range information');
+        }
+
+        // tokens array is empty, we attach comments to tree as 'leadingComments'
+        if (!tokens.length) {
+            if (providedComments.length) {
+                for (i = 0, len = providedComments.length; i < len; i += 1) {
+                    comment = deepCopy(providedComments[i]);
+                    comment.extendedRange = [0, tree.range[0]];
+                    comments.push(comment);
+                }
+                tree.leadingComments = comments;
+            }
+            return tree;
+        }
+
+        for (i = 0, len = providedComments.length; i < len; i += 1) {
+            comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
+        }
+
+        // This is based on John Freeman's implementation.
+        traverse(tree, {
+            cursor: 0,
+            enter: function (node) {
+                var comment;
+
+                while (this.cursor < comments.length) {
+                    comment = comments[this.cursor];
+                    if (comment.extendedRange[1] > node.range[0]) {
+                        break;
+                    }
+
+                    if (comment.extendedRange[1] === node.range[0]) {
+                        if (!node.leadingComments) {
+                            node.leadingComments = [];
+                        }
+                        node.leadingComments.push(comment);
+                        comments.splice(this.cursor, 1);
+                    } else {
+                        this.cursor += 1;
+                    }
+                }
+
+                // already out of owned node
+                if (this.cursor === comments.length) {
+                    return VisitorOption.Break;
+                }
+
+                if (comments[this.cursor].extendedRange[0] > node.range[1]) {
+                    return VisitorOption.Skip;
+                }
+            }
+        });
+
+        traverse(tree, {
+            cursor: 0,
+            leave: function (node) {
+                var comment;
+
+                while (this.cursor < comments.length) {
+                    comment = comments[this.cursor];
+                    if (node.range[1] < comment.extendedRange[0]) {
+                        break;
+                    }
+
+                    if (node.range[1] === comment.extendedRange[0]) {
+                        if (!node.trailingComments) {
+                            node.trailingComments = [];
+                        }
+                        node.trailingComments.push(comment);
+                        comments.splice(this.cursor, 1);
+                    } else {
+                        this.cursor += 1;
+                    }
+                }
+
+                // already out of owned node
+                if (this.cursor === comments.length) {
+                    return VisitorOption.Break;
+                }
+
+                if (comments[this.cursor].extendedRange[0] > node.range[1]) {
+                    return VisitorOption.Skip;
+                }
+            }
+        });
+
+        return tree;
+    }
+
+    // Sync with package.json.
+    exports.version = '0.0.16-dev';
+
+    exports.generate = generate;
+    exports.attachComments = attachComments;
+    exports.browser = false;
+}());
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+});
+
+require.define("/node_modules/estraverse/package.json",function(require,module,exports,__dirname,__filename,process,global){module.exports = {"main":"estraverse.js"}
+});
+
+require.define("/node_modules/estraverse/estraverse.js",function(require,module,exports,__dirname,__filename,process,global){/*
+  Copyright (C) 2012 Yusuke Suzuki <ut...@gmail.com>
+  Copyright (C) 2012 Ariya Hidayat <ar...@gmail.com>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+  'use strict';
+
+  var Syntax,
+      isArray,
+      VisitorOption,
+      VisitorKeys,
+      wrappers;
+
+  Syntax = {
+      AssignmentExpression: 'AssignmentExpression',
+      ArrayExpression: 'ArrayExpression',
+      BlockStatement: 'BlockStatement',
+      BinaryExpression: 'BinaryExpression',
+      BreakStatement: 'BreakStatement',
+      CallExpression: 'CallExpression',
+      CatchClause: 'CatchClause',
+      ConditionalExpression: 'ConditionalExpression',
+      ContinueStatement: 'ContinueStatement',
+      DebuggerStatement: 'DebuggerStatement',
+      DirectiveStatement: 'DirectiveStatement',
+      DoWhileStatement: 'DoWhileStatement',
+      EmptyStatement: 'EmptyStatement',
+      ExpressionStatement: 'ExpressionStatement',
+      ForStatement: 'ForStatement',
+      ForInStatement: 'ForInStatement',
+      FunctionDeclaration: 'FunctionDeclaration',
+      FunctionExpression: 'FunctionExpression',
+      Identifier: 'Identifier',
+      IfStatement: 'IfStatement',
+      Literal: 'Literal',
+      LabeledStatement: 'LabeledStatement',
+      LogicalExpression: 'LogicalExpression',
+      MemberExpression: 'MemberExpression',
+      NewExpression: 'NewExpression',
+      ObjectExpression: 'ObjectExpression',
+      Program: 'Program',
+      Property: 'Property',
+      ReturnStatement: 'ReturnStatement',
+      SequenceExpression: 'SequenceExpression',
+      SwitchStatement: 'SwitchStatement',
+      SwitchCase: 'SwitchCase',
+      ThisExpression: 'ThisExpression',
+      ThrowStatement: 'ThrowStatement',
+      TryStatement: 'TryStatement',
+      UnaryExpression: 'UnaryExpression',
+      UpdateExpression: 'UpdateExpression',
+      VariableDeclaration: 'VariableDeclaration',
+      VariableDeclarator: 'VariableDeclarator',
+      WhileStatement: 'WhileStatement',
+      WithStatement: 'WithStatement'
+  };
+
+  isArray = Array.isArray;
+  if (!isArray) {
+      isArray = function isArray(array) {
+          return Object.prototype.toString.call(array) === '[object Array]';
+      };
+  }
+
+  VisitorKeys = {
+      AssignmentExpression: ['left', 'right'],
+      ArrayExpression: ['elements'],
+      BlockStatement: ['body'],
+      BinaryExpression: ['left', 'right'],
+      BreakStatement: ['label'],
+      CallExpression: ['callee', 'arguments'],
+      CatchClause: ['param', 'body'],
+      ConditionalExpression: ['test', 'consequent', 'alternate'],
+      ContinueStatement: ['label'],
+      DebuggerStatement: [],
+      DirectiveStatement: [],
+      DoWhileStatement: ['body', 'test'],
+      EmptyStatement: [],
+      ExpressionStatement: ['expression'],
+      ForStatement: ['init', 'test', 'update', 'body'],
+      ForInStatement: ['left', 'right', 'body'],
+      FunctionDeclaration: ['id', 'params', 'body'],
+      FunctionExpression: ['id', 'params', 'body'],
+      Identifier: [],
+      IfStatement: ['test', 'consequent', 'alternate'],
+      Literal: [],
+      LabeledStatement: ['label', 'body'],
+      LogicalExpression: ['left', 'right'],
+      MemberExpression: ['object', 'property'],
+      NewExpression: ['callee', 'arguments'],
+      ObjectExpression: ['properties'],
+      Program: ['body'],
+      Property: ['key', 'value'],
+      ReturnStatement: ['argument'],
+      SequenceExpression: ['expressions'],
+      SwitchStatement: ['discriminant', 'cases'],
+      SwitchCase: ['test', 'consequent'],
+      ThisExpression: [],
+      ThrowStatement: ['argument'],
+      TryStatement: ['block', 'handlers', 'finalizer'],
+      UnaryExpression: ['argument'],
+      UpdateExpression: ['argument'],
+      VariableDeclaration: ['declarations'],
+      VariableDeclarator: ['id', 'init'],
+      WhileStatement: ['test', 'body'],
+      WithStatement: ['object', 'body']
+  };
+
+  VisitorOption = {
+      Break: 1,
+      Skip: 2
+  };
+
+  wrappers = {
+      PropertyWrapper: 'Property'
+  };
+
+  function traverse(top, visitor) {
+      var worklist, leavelist, node, nodeType, ret, current, current2, candidates, candidate, marker = {};
+
+      worklist = [ top ];
+      leavelist = [ null ];
+
+      while (worklist.length) {
+          node = worklist.pop();
+          nodeType = node.type;
+
+          if (node === marker) {
+              node = leavelist.pop();
+              if (visitor.leave) {
+                  ret = visitor.leave(node, leavelist[leavelist.length - 1]);
+              } else {
+                  ret = undefined;
+              }
+              if (ret === VisitorOption.Break) {
+                  return;
+              }
+          } else if (node) {
+              if (wrappers.hasOwnProperty(nodeType)) {
+                  node = node.node;
+                  nodeType = wrappers[nodeType];
+              }
+
+              if (visitor.enter) {
+                  ret = visitor.enter(node, leavelist[leavelist.length - 1]);
+              } else {
+                  ret = undefined;
+              }
+
+              if (ret === VisitorOption.Break) {
+                  return;
+              }
+
+              worklist.push(marker);
+              leavelist.push(node);
+
+              if (ret !== VisitorOption.Skip) {
+                  candidates = VisitorKeys[nodeType];
+                  current = candidates.length;
+                  while ((current -= 1) >= 0) {
+                      candidate = node[candidates[current]];
+                      if (candidate) {
+                          if (isArray(candidate)) {
+                              current2 = candidate.length;
+                              while ((current2 -= 1) >= 0) {
+                                  if (candidate[current2]) {
+                                      if(nodeType === Syntax.ObjectExpression && 'properties' === candidates[current] && null == candidates[current].type) {
+                                          worklist.push({type: 'PropertyWrapper', node: candidate[current2]});
+                                      } else {
+                                          worklist.push(candidate[current2]);
+                                      }
+                                  }
+                              }
+                          } else {
+                              worklist.push(candidate);
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  }
+
+  function replace(top, visitor) {
+      var worklist, leavelist, node, nodeType, target, tuple, ret, current, current2, candidates, candidate, marker = {}, result;
+
+      result = {
+          top: top
+      };
+
+      tuple = [ top, result, 'top' ];
+      worklist = [ tuple ];
+      leavelist = [ tuple ];
+
+      function notify(v) {
+          ret = v;
+      }
+
+      while (worklist.length) {
+          tuple = worklist.pop();
+
+          if (tuple === marker) {
+              tuple = leavelist.pop();
+              ret = undefined;
+              if (visitor.leave) {
+                  node = tuple[0];
+                  target = visitor.leave(tuple[0], leavelist[leavelist.length - 1][0], notify);
+                  if (target !== undefined) {
+                      node = target;
+                  }
+                  tuple[1][tuple[2]] = node;
+              }
+              if (ret === VisitorOption.Break) {
+                  return result.top;
+              }
+          } else if (tuple[0]) {
+              ret = undefined;
+              node = tuple[0];
+
+              nodeType = node.type;
+              if (wrappers.hasOwnProperty(nodeType)) {
+                  tuple[0] = node = node.node;
+                  nodeType = wrappers[nodeType];
+              }
+
+              if (visitor.enter) {
+                  target = visitor.enter(tuple[0], leavelist[leavelist.length - 1][0], notify);
+                  if (target !== undefined) {
+                      node = target;
+                  }
+                  tuple[1][tuple[2]] = node;
+                  tuple[0] = node;
+              }
+
+              if (ret === VisitorOption.Break) {
+                  return result.top;
+              }
+
+              if (tuple[0]) {
+                  worklist.push(marker);
+                  leavelist.push(tuple);
+
+                  if (ret !== VisitorOption.Skip) {
+                      candidates = VisitorKeys[nodeType];
+                      current = candidates.length;
+                      while ((current -= 1) >= 0) {
+                          candidate = node[candidates[current]];
+                          if (candidate) {
+                              if (isArray(candidate)) {
+                                  current2 = candidate.length;
+                                  while ((current2 -= 1) >= 0) {
+                                      if (candidate[current2]) {
+                                          if(nodeType === Syntax.ObjectExpression && 'properties' === candidates[current] && null == candidates[current].type) {
+                                              worklist.push([{type: 'PropertyWrapper', node: candidate[current2]}, candidate, current2]);
+                                          } else {
+                                              worklist.push([candidate[current2], candidate, current2]);
+                                          }
+                                      }
+                                  }
+                              } else {
+                                  worklist.push([candidate, node, candidates[current]]);
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+
+      return result.top;
+  }
+
+  exports.version = '0.0.4';
+  exports.Syntax = Syntax;
+  exports.traverse = traverse;
+  exports.replace = replace;
+  exports.VisitorKeys = VisitorKeys;
+  exports.VisitorOption = VisitorOption;
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+});
+
+require.define("/tools/entry-point.js",function(require,module,exports,__dirname,__filename,process,global){/*
+  Copyright (C) 2012 Yusuke Suzuki <ut...@gmail.com>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+(function () {
+    'use strict';
+    var escodegen;
+    escodegen = global.escodegen = require('../escodegen');
+    escodegen.browser = true;
+}());
+
+});
+require("/tools/entry-point.js");
+})();
+
diff --git a/builder/lib/esl.js b/builder/lib/esl.js
new file mode 100644
index 0000000..206ea64
--- /dev/null
+++ b/builder/lib/esl.js
@@ -0,0 +1,1643 @@
+/**
+ * ESL (Enterprise Standard Loader)
+ * Copyright 2013 Baidu Inc. All rights reserved.
+ *
+ * @file Browser端标准加载器,符合AMD规范
+ * @author errorrik(errorrik@gmail.com)
+ *         Firede(firede@firede.us)
+ */
+
+/* jshint ignore:start */
+var define;
+var require;
+var esl;
+/* jshint ignore:end */
+
+/* eslint-disable guard-for-in */
+/* eslint-env amd:false */
+
+(function (global) {
+    // "mod"开头的变量或函数为内部模块管理函数
+    // 为提高压缩率,不使用function或object包装
+
+    /**
+     * 模块容器
+     *
+     * @inner
+     * @type {Object}
+     */
+    var modModules = {};
+
+    // 模块状态枚举量
+    var MODULE_PRE_DEFINED = 1;
+    var MODULE_ANALYZED = 2;
+    var MODULE_PREPARED = 3;
+    var MODULE_DEFINED = 4;
+
+    /**
+     * 自动定义的模块表
+     *
+     * 模块define factory是用到时才执行,但是以下几种情况需要自动马上执行:
+     * 1. require([moduleId], callback)
+     * 2. plugin module and plugin resource: require('plugin!resource')
+     * 3. shim module
+     *
+     * @inner
+     * @type {Object}
+     */
+    var modAutoDefineModules = {};
+
+    /**
+     * 标记模块自动进行定义
+     *
+     * @inner
+     * @param {string} id 模块id
+     */
+    function modFlagAutoDefine(id) {
+        if (!modIs(id, MODULE_DEFINED)) {
+            modAutoDefineModules[id] = 1;
+        }
+    }
+
+    /**
+     * 内建module名称集合
+     *
+     * @inner
+     * @type {Object}
+     */
+    var BUILDIN_MODULE = {
+        require: globalRequire,
+        exports: 1,
+        module: 1
+    };
+
+    /**
+     * 全局require函数
+     *
+     * @inner
+     * @type {Function}
+     */
+    var actualGlobalRequire = createLocalRequire();
+
+    // #begin-ignore
+    /**
+     * 超时提醒定时器
+     *
+     * @inner
+     * @type {number}
+     */
+    var waitTimeout;
+    // #end-ignore
+
+    /* eslint-disable fecs-key-spacing */
+    /* eslint-disable key-spacing */
+    /**
+     * require配置
+     *
+     * @inner
+     * @type {Object}
+     */
+    var requireConf = {
+        baseUrl    : './',
+        paths      : {},
+        config     : {},
+        map        : {},
+        packages   : [],
+        shim       : {},
+        // #begin-ignore
+        waitSeconds: 0,
+        // #end-ignore
+        bundles    : {},
+        urlArgs    : {}
+    };
+    /* eslint-enable key-spacing */
+
+    /**
+     * 加载模块
+     *
+     * @param {string|Array} requireId 模块id或模块id数组,
+     * @param {Function=} callback 加载完成的回调函数
+     * @return {*} requireId为string时返回模块暴露对象
+     */
+    function globalRequire(requireId, callback) {
+        // #begin-ignore
+        // #begin assertNotContainRelativeId
+        // 确定require的模块id不包含相对id。用于global require,提前预防难以跟踪的错误出现
+        var invalidIds = [];
+
+        /**
+         * 监测模块id是否relative id
+         *
+         * @inner
+         * @param {string} id 模块id
+         */
+        function monitor(id) {
+            if (id.indexOf('.') === 0) {
+                invalidIds.push(id);
+            }
+        }
+
+        if (typeof requireId === 'string') {
+            monitor(requireId);
+        }
+        else {
+            each(
+                requireId,
+                function (id) {
+                    monitor(id);
+                }
+            );
+        }
+
+        // 包含相对id时,直接抛出错误
+        if (invalidIds.length > 0) {
+            throw new Error(
+                '[REQUIRE_FATAL]Relative ID is not allowed in global require: '
+                + invalidIds.join(', ')
+            );
+        }
+        // #end assertNotContainRelativeId
+
+        // 超时提醒
+        var timeout = requireConf.waitSeconds;
+        if (timeout && (requireId instanceof Array)) {
+            if (waitTimeout) {
+                clearTimeout(waitTimeout);
+            }
+            waitTimeout = setTimeout(waitTimeoutNotice, timeout * 1000);
+        }
+        // #end-ignore
+
+        return actualGlobalRequire(requireId, callback);
+    }
+
+    /**
+     * 版本号
+     *
+     * @type {string}
+     */
+    globalRequire.version = '2.0.4';
+
+    /**
+     * loader名称
+     *
+     * @type {string}
+     */
+    globalRequire.loader = 'esl';
+
+    /**
+     * 将模块标识转换成相对的url
+     *
+     * @param {string} id 模块标识
+     * @return {string}
+     */
+    globalRequire.toUrl = actualGlobalRequire.toUrl;
+
+    // #begin-ignore
+    /**
+     * 超时提醒函数
+     *
+     * @inner
+     */
+    function waitTimeoutNotice() {
+        var hangModules = [];
+        var missModules = [];
+        var hangModulesMap = {};
+        var missModulesMap = {};
+        var visited = {};
+
+        /**
+         * 检查模块的加载错误
+         *
+         * @inner
+         * @param {string} id 模块id
+         * @param {boolean} hard 是否装载时依赖
+         */
+        function checkError(id, hard) {
+            if (visited[id] || modIs(id, MODULE_DEFINED)) {
+                return;
+            }
+
+            visited[id] = 1;
+
+            if (!modIs(id, MODULE_PREPARED)) {
+                // HACK: 为gzip后体积优化,不做抽取
+                if (!hangModulesMap[id]) {
+                    hangModulesMap[id] = 1;
+                    hangModules.push(id);
+                }
+            }
+
+            var mod = modModules[id];
+            if (!mod) {
+                if (!missModulesMap[id]) {
+                    missModulesMap[id] = 1;
+                    missModules.push(id);
+                }
+            }
+            else if (hard) {
+                if (!hangModulesMap[id]) {
+                    hangModulesMap[id] = 1;
+                    hangModules.push(id);
+                }
+
+                each(
+                    mod.depMs,
+                    function (dep) {
+                        checkError(dep.absId, dep.hard);
+                    }
+                );
+            }
+        }
+
+        for (var id in modAutoDefineModules) {
+            checkError(id, 1);
+        }
+
+        if (hangModules.length || missModules.length) {
+            throw new Error(
+                '[MODULE_TIMEOUT]Hang( '
+                + (hangModules.join(', ') || 'none')
+                + ' ) Miss( '
+                + (missModules.join(', ') || 'none')
+                + ' )'
+            );
+        }
+    }
+    // #end-ignore
+
+    /**
+     * 未预定义的模块集合
+     * 主要存储匿名方式define的模块
+     *
+     * @inner
+     * @type {Array}
+     */
+    var wait4PreDefine = [];
+
+    /**
+     * 完成模块预定义,此时处理的模块是匿名define的模块
+     *
+     * @inner
+     * @param {string} currentId 匿名define的模块的id
+     */
+    function modCompletePreDefine(currentId) {
+        // HACK: 这里在IE下有个性能陷阱,不能使用任何变量。
+        //       否则貌似会形成变量引用和修改的读写锁,导致wait4PreDefine释放困难
+        each(wait4PreDefine, function (mod) {
+            modPreDefine(
+                currentId,
+                mod.deps,
+                mod.factory
+            );
+        });
+
+        wait4PreDefine.length = 0;
+    }
+
+    /**
+     * 定义模块
+     *
+     * @param {string=} id 模块标识
+     * @param {Array=} dependencies 依赖模块列表
+     * @param {Function=} factory 创建模块的工厂方法
+     */
+    function globalDefine(id, dependencies, factory) {
+        // define(factory)
+        // define(dependencies, factory)
+        // define(id, factory)
+        // define(id, dependencies, factory)
+        if (factory == null) {
+            if (dependencies == null) {
+                factory = id;
+                id = null;
+            }
+            else {
+                factory = dependencies;
+                dependencies = null;
+                if (id instanceof Array) {
+                    dependencies = id;
+                    id = null;
+                }
+            }
+        }
+
+        if (factory == null) {
+            return;
+        }
+
+        var opera = window.opera;
+
+        // IE下通过current script的data-require-id获取当前id
+        if (
+            !id
+            && document.attachEvent
+            && (!(opera && opera.toString() === '[object Opera]'))
+        ) {
+            var currentScript = getCurrentScript();
+            id = currentScript && currentScript.getAttribute('data-require-id');
+        }
+
+        if (id) {
+            modPreDefine(id, dependencies, factory);
+        }
+        else {
+            // 纪录到共享变量中,在load或readystatechange中处理
+            // 标准浏览器下,使用匿名define时,将进入这个分支
+            wait4PreDefine[0] = {
+                deps: dependencies,
+                factory: factory
+            };
+        }
+    }
+
+    globalDefine.amd = {};
+
+    /**
+     * 模块配置获取函数
+     *
+     * @inner
+     * @return {Object} 模块配置对象
+     */
+    function moduleConfigGetter() {
+        var conf = requireConf.config[this.id];
+        if (conf && typeof conf === 'object') {
+            return conf;
+        }
+
+        return {};
+    }
+
+    /**
+     * 预定义模块
+     *
+     * @inner
+     * @param {string} id 模块标识
+     * @param {Array.<string>} dependencies 显式声明的依赖模块列表
+     * @param {*} factory 模块定义函数或模块对象
+     */
+    function modPreDefine(id, dependencies, factory) {
+        // 将模块存入容器
+        //
+        // 模块内部信息包括
+        // -----------------------------------
+        // id: module id
+        // depsDec: 模块定义时声明的依赖
+        // deps: 模块依赖,默认为['require', 'exports', 'module']
+        // factory: 初始化函数或对象
+        // factoryDeps: 初始化函数的参数依赖
+        // exports: 模块的实际暴露对象(AMD定义)
+        // config: 用于获取模块配置信息的函数(AMD定义)
+        // state: 模块当前状态
+        // require: local require函数
+        // depMs: 实际依赖的模块集合,数组形式
+        // depMkv: 实际依赖的模块集合,表形式,便于查找
+        // depRs: 实际依赖的资源集合
+        // ------------------------------------
+        if (!modModules[id]) {
+            /* eslint-disable key-spacing */
+            modModules[id] = {
+                id          : id,
+                depsDec     : dependencies,
+                deps        : dependencies || ['require', 'exports', 'module'],
+                factoryDeps : [],
+                factory     : factory,
+                exports     : {},
+                config      : moduleConfigGetter,
+                state       : MODULE_PRE_DEFINED,
+                require     : createLocalRequire(id),
+                depMs       : [],
+                depMkv      : {},
+                depRs       : []
+            };
+            /* eslint-enable key-spacing */
+        }
+    }
+
+    /**
+     * 开始执行模块定义前的准备工作
+     *
+     * 首先,完成对factory中声明依赖的分析提取
+     * 然后,尝试加载"资源加载所需模块"
+     *
+     * 需要先加载模块的原因是:如果模块不存在,无法进行resourceId normalize化
+     *
+     * @inner
+     * @param {string} id 模块id
+     */
+    function modPrepare(id) {
+        var mod = modModules[id];
+        if (!mod || modIs(id, MODULE_ANALYZED)) {
+            return;
+        }
+
+        var deps = mod.deps;
+        var factory = mod.factory;
+        var hardDependsCount = 0;
+
+        // 分析function body中的require
+        // 如果包含显式依赖声明,根据AMD规定和性能考虑,可以不分析factoryBody
+        if (typeof factory === 'function') {
+            hardDependsCount = Math.min(factory.length, deps.length);
+
+            // If the dependencies argument is present, the module loader
+            // SHOULD NOT scan for dependencies within the factory function.
+            !mod.depsDec && factory.toString()
+                .replace(/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, '')
+                .replace(/require\(\s*(['"'])([^'"]+)\1\s*\)/g,
+                    function ($0, $1, depId) {
+                        deps.push(depId);
+                    }
+                );
+        }
+
+        var requireModules = [];
+        var depResources = [];
+        each(deps, function (depId, index) {
+            var idInfo = parseId(depId);
+            var absId = normalize(idInfo.mod, id);
+            var moduleInfo;
+            var resInfo;
+
+            if (absId && !BUILDIN_MODULE[absId]) {
+                // 如果依赖是一个资源,将其信息添加到module.depRs
+                //
+                // module.depRs中的项有可能是重复的。
+                // 在这个阶段,加载resource的module可能还未defined,
+                // 导致此时resource id无法被normalize。
+                //
+                // 比如对a/b/c而言,下面几个resource可能指的是同一个资源:
+                // - js!../name.js
+                // - js!a/name.js
+                // - ../../js!../name.js
+                //
+                // 所以加载资源的module ready时,需要遍历module.depRs进行处理
+                if (idInfo.res) {
+                    resInfo = {
+                        id: depId,
+                        mod: absId,
+                        res: idInfo.res
+                    };
+                    depResources.push(depId);
+                    mod.depRs.push(resInfo);
+                }
+
+                // 对依赖模块的id normalize能保证正确性,在此处进行去重
+                moduleInfo = mod.depMkv[absId];
+                if (!moduleInfo) {
+                    moduleInfo = {
+                        id: idInfo.mod,
+                        absId: absId,
+                        hard: index < hardDependsCount
+                    };
+                    mod.depMs.push(moduleInfo);
+                    mod.depMkv[absId] = moduleInfo;
+                    requireModules.push(absId);
+                }
+            }
+            else {
+                moduleInfo = {absId: absId};
+            }
+
+            // 如果当前正在分析的依赖项是define中声明的,
+            // 则记录到module.factoryDeps中
+            // 在factory invoke前将用于生成invoke arguments
+            if (index < hardDependsCount) {
+                mod.factoryDeps.push(resInfo || moduleInfo);
+            }
+        });
+
+        mod.state = MODULE_ANALYZED;
+        modInitFactoryInvoker(id);
+        nativeAsyncRequire(requireModules);
+        depResources.length && mod.require(
+            depResources,
+            function () {
+                each(mod.depRs, function (res) {
+                    if (!res.absId) {
+                        res.absId = normalize(res.id, id);
+                    }
+                });
+                modAutoDefine();
+            }
+        );
+    }
+
+    /**
+     * 对一些需要自动定义的模块进行自动定义
+     *
+     * @inner
+     */
+    function modAutoDefine() {
+        for (var id in modAutoDefineModules) {
+            modPrepare(id);
+            modUpdatePreparedState(id);
+            modTryInvokeFactory(id);
+        }
+    }
+
+    /**
+     * 更新模块的准备状态
+     *
+     * @inner
+     * @param {string} id 模块id
+     */
+    function modUpdatePreparedState(id) {
+        var visited = {};
+        update(id);
+
+        function update(id) {
+            modPrepare(id);
+            if (!modIs(id, MODULE_ANALYZED)) {
+                return false;
+            }
+            if (modIs(id, MODULE_PREPARED) || visited[id]) {
+                return true;
+            }
+
+            visited[id] = 1;
+            var mod = modModules[id];
+            var prepared = true;
+
+            each(
+                mod.depMs,
+                function (dep) {
+                    return (prepared = update(dep.absId));
+                }
+            );
+
+            // 判断resource是否加载完成。如果resource未加载完成,则认为未准备好
+            /* jshint ignore:start */
+            prepared && each(
+                mod.depRs,
+                function (dep) {
+                    prepared = !!dep.absId;
+                    return prepared;
+                }
+            );
+            /* jshint ignore:end */
+
+            if (prepared && !modIs(id, MODULE_PREPARED)) {
+                mod.state = MODULE_PREPARED;
+            }
+
+            return prepared;
+        }
+    }
+
+    /**
+     * 初始化模块定义时所需的factory执行器
+     *
+     * @inner
+     * @param {string} id 模块id
+     */
+    function modInitFactoryInvoker(id) {
+        var mod = modModules[id];
+        var invoking;
+
+        mod.invokeFactory = invokeFactory;
+
+        /**
+         * 初始化模块
+         *
+         * @inner
+         */
+        function invokeFactory() {
+            if (invoking || mod.state !== MODULE_PREPARED) {
+                return;
+            }
+
+            invoking = 1;
+
+            // 拼接factory invoke所需的arguments
+            var factoryReady = 1;
+            each(
+                mod.factoryDeps,
+                function (dep) {
+                    var depId = dep.absId;
+
+                    if (!BUILDIN_MODULE[depId]) {
+                        modTryInvokeFactory(depId);
+                        return (factoryReady = modIs(depId, MODULE_DEFINED));
+                    }
+                }
+            );
+
+            if (factoryReady) {
+                try {
+                    // 调用factory函数初始化module
+                    var factory = mod.factory;
+                    var exports = typeof factory === 'function'
+                        ? factory.apply(global, modGetModulesExports(
+                                mod.factoryDeps,
+                                {
+                                    require: mod.require,
+                                    exports: mod.exports,
+                                    module: mod
+                                }
+                            ))
+                        : factory;
+
+                    if (exports != null) {
+                        mod.exports = exports;
+                    }
+
+                    mod.invokeFactory = null;
+                }
+                catch (ex) {
+                    if (/^\[MODULE_MISS\]"([^"]+)/.test(ex.message)) {
+                        // 出错,则说明在factory的运行中,该require的模块是需要的
+                        // 所以把它加入强依赖中
+                        var hardCirclurDep = mod.depMkv[RegExp.$1];
+                        hardCirclurDep && (hardCirclurDep.hard = 1);
+
+                        // 如果是模块本身有问题导致的运行错误
+                        // 就不要把invoking置回去了,避免影响autoInvoke其他模块的初始化
+                        invoking = 0;
+                        return;
+                    }
+
+                    throw ex;
+                }
+
+                // 完成define
+                // 不放在try里,避免后续的运行错误被这里吞掉
+                modDefined(id);
+            }
+        }
+    }
+
+    /**
+     * 判断模块是否完成相应的状态
+     *
+     * @inner
+     * @param {string} id 模块标识
+     * @param {number} state 状态码,使用时传入相应的枚举变量,比如`MODULE_DEFINED`
+     * @return {boolean} 是否完成相应的状态
+     */
+    function modIs(id, state) {
+        return modModules[id] && modModules[id].state >= state;
+    }
+
+    /**
+     * 尝试执行模块factory函数,进行模块初始化
+     *
+     * @inner
+     * @param {string} id 模块id
+     */
+    function modTryInvokeFactory(id) {
+        var mod = modModules[id];
+
+        if (mod && mod.invokeFactory) {
+            mod.invokeFactory();
+        }
+    }
+
+    /**
+     * 根据模块id数组,获取其的exports数组
+     * 用于模块初始化的factory参数或require的callback参数生成
+     *
+     * @inner
+     * @param {Array} modules 模块id数组
+     * @param {Object} buildinModules 内建模块对象
+     * @return {Array} 模块exports数组
+     */
+    function modGetModulesExports(modules, buildinModules) {
+        var args = [];
+        each(
+            modules,
+            function (id, index) {
+                if (typeof id === 'object') {
+                    id = id.absId;
+                }
+                args[index] = buildinModules[id] || modModules[id].exports;
+            }
+        );
+
+        return args;
+    }
+
+    /**
+     * 模块定义完成事件监听器容器
+     *
+     * @inner
+     * @type {Object}
+     */
+    var modDefinedListeners = {};
+
+    /**
+     * 添加模块定义完成时间的监听器
+     *
+     * @inner
+     * @param {string} id 模块标识
+     * @param {Function} listener 监听函数
+     */
+    function modAddDefinedListener(id, listener) {
+        if (modIs(id, MODULE_DEFINED)) {
+            listener();
+            return;
+        }
+
+        var listeners = modDefinedListeners[id];
+        if (!listeners) {
+            listeners = modDefinedListeners[id] = [];
+        }
+
+        listeners.push(listener);
+    }
+
+    /**
+     * 模块状态切换为定义完成
+     * 因为需要触发事件,MODULE_DEFINED状态切换通过该函数
+     *
+     * @inner
+     * @param {string} id 模块标识
+     */
+    function modDefined(id) {
+        var mod = modModules[id];
+        mod.state = MODULE_DEFINED;
+        delete modAutoDefineModules[id];
+
+        var listeners = modDefinedListeners[id] || [];
+        var len = listeners.length;
+        while (len--) {
+            // 这里不做function类型的检测
+            // 因为listener都是通过modOn传入的,modOn为内部调用
+            listeners[len]();
+        }
+
+        // 清理listeners
+        listeners.length = 0;
+        modDefinedListeners[id] = null;
+    }
+
+    /**
+     * 异步加载模块
+     * 内部使用,模块ID必须是经过normalize的Top-Level ID
+     *
+     * @inner
+     * @param {Array} ids 模块名称或模块名称列表
+     * @param {Function=} callback 获取模块完成时的回调函数
+     * @param {string} baseId 基础id,用于当ids是relative id时的normalize
+     */
+    function nativeAsyncRequire(ids, callback, baseId) {
+        var isCallbackCalled = 0;
+
+        each(ids, function (id) {
+            if (!(BUILDIN_MODULE[id] || modIs(id, MODULE_DEFINED))) {
+                modAddDefinedListener(id, tryFinishRequire);
+                (id.indexOf('!') > 0
+                    ? loadResource
+                    : loadModule
+                )(id, baseId);
+            }
+        });
+        tryFinishRequire();
+
+        /**
+         * 尝试完成require,调用callback
+         * 在模块与其依赖模块都加载完时调用
+         *
+         * @inner
+         */
+        function tryFinishRequire() {
+            if (typeof callback === 'function' && !isCallbackCalled) {
+                var isAllCompleted = 1;
+                each(ids, function (id) {
+                    if (!BUILDIN_MODULE[id]) {
+                        return (isAllCompleted = !!modIs(id, MODULE_DEFINED));
+                    }
+                });
+
+                // 检测并调用callback
+                if (isAllCompleted) {
+                    isCallbackCalled = 1;
+
+                    callback.apply(
+                        global,
+                        modGetModulesExports(ids, BUILDIN_MODULE)
+                    );
+                }
+            }
+        }
+    }
+
+    /**
+     * 正在加载的模块列表
+     *
+     * @inner
+     * @type {Object}
+     */
+    var loadingModules = {};
+
+    /**
+     * 加载模块
+     *
+     * @inner
+     * @param {string} moduleId 模块标识
+     */
+    function loadModule(moduleId) {
+        // 加载过的模块,就不要再继续了
+        if (loadingModules[moduleId] || modModules[moduleId]) {
+            return;
+        }
+        loadingModules[moduleId] = 1;
+
+        // 初始化相关 shim 的配置
+        var shimConf = requireConf.shim[moduleId];
+        if (shimConf instanceof Array) {
+            requireConf.shim[moduleId] = shimConf = {
+                deps: shimConf
+            };
+        }
+
+        // shim依赖的模块需要自动标识为shim
+        // 无论是纯正的shim模块还是hybird模块
+        var shimDeps = shimConf && (shimConf.deps || []);
+        if (shimDeps) {
+            each(shimDeps, function (dep) {
+                if (!requireConf.shim[dep]) {
+                    requireConf.shim[dep] = {};
+                }
+            });
+            actualGlobalRequire(shimDeps, load);
+        }
+        else {
+            load();
+        }
+
+        /**
+         * 发送请求去加载模块
+         *
+         * @inner
+         */
+        function load() {
+            /* eslint-disable no-use-before-define */
+            var bundleModuleId = bundlesIndex[moduleId];
+            createScript(bundleModuleId || moduleId, loaded);
+            /* eslint-enable no-use-before-define */
+        }
+
+        /**
+         * script标签加载完成的事件处理函数
+         *
+         * @inner
+         */
+        function loaded() {
+            if (shimConf) {
+                var exports;
+                if (typeof shimConf.init === 'function') {
+                    exports = shimConf.init.apply(
+                        global,
+                        modGetModulesExports(shimDeps, BUILDIN_MODULE)
+                    );
+                }
+
+                if (exports == null && shimConf.exports) {
+                    exports = global;
+                    each(
+                        shimConf.exports.split('.'),
+                        function (prop) {
+                            exports = exports[prop];
+                            return !!exports;
+                        }
+                    );
+                }
+
+                globalDefine(moduleId, shimDeps, exports || {});
+            }
+            else {
+                modCompletePreDefine(moduleId);
+            }
+
+            modAutoDefine();
+        }
+    }
+
+    /**
+     * 加载资源
+     *
+     * @inner
+     * @param {string} pluginAndResource 插件与资源标识
+     * @param {string} baseId 当前环境的模块标识
+     */
+    function loadResource(pluginAndResource, baseId) {
+        if (modModules[pluginAndResource]) {
+            return;
+        }
+
+        /* eslint-disable no-use-before-define */
+        var bundleModuleId = bundlesIndex[pluginAndResource];
+        if (bundleModuleId) {
+            loadModule(bundleModuleId);
+            return;
+        }
+        /* eslint-enable no-use-before-define */
+
+        var idInfo = parseId(pluginAndResource);
+        var resource = {
+            id: pluginAndResource,
+            state: MODULE_ANALYZED
+        };
+        modModules[pluginAndResource] = resource;
+
+        /**
+         * plugin加载完成的回调函数
+         *
+         * @inner
+         * @param {*} value resource的值
+         */
+        function pluginOnload(value) {
+            resource.exports = value || true;
+            modDefined(pluginAndResource);
+        }
+
+        /* jshint ignore:start */
+        /**
+         * 该方法允许plugin使用加载的资源声明模块
+         *
+         * @param {string} id 模块id
+         * @param {string} text 模块声明字符串
+         */
+        pluginOnload.fromText = function (id, text) {
+            new Function(text)();
+            modCompletePreDefine(id);
+        };
+        /* jshint ignore:end */
+
+        /**
+         * 加载资源
+         *
+         * @inner
+         * @param {Object} plugin 用于加载资源的插件模块
+         */
+        function load(plugin) {
+            var pluginRequire = baseId
+                ? modModules[baseId].require
+                : actualGlobalRequire;
+
+            plugin.load(
+                idInfo.res,
+                pluginRequire,
+                pluginOnload,
+                moduleConfigGetter.call({id: pluginAndResource})
+            );
+        }
+
+        load(actualGlobalRequire(idInfo.mod));
+    }
+
+    /**
+     * 配置require
+     *
+     * @param {Object} conf 配置对象
+     */
+    globalRequire.config = function (conf) {
+        if (conf) {
+            for (var key in requireConf) {
+                var newValue = conf[key];
+                var oldValue = requireConf[key];
+
+                if (!newValue) {
+                    continue;
+                }
+
+                if (key === 'urlArgs' && typeof newValue === 'string') {
+                    requireConf.urlArgs['*'] = newValue;
+                }
+                else {
+                    // 简单的多处配置还是需要支持,所以配置实现为支持二级mix
+                    if (oldValue instanceof Array) {
+                        oldValue.push.apply(oldValue, newValue);
+                    }
+                    else if (typeof oldValue === 'object') {
+                        for (var k in newValue) {
+                            oldValue[k] = newValue[k];
+                        }
+                    }
+                    else {
+                        requireConf[key] = newValue;
+                    }
+                }
+            }
+
+            createConfIndex();
+        }
+    };
+
+    // 初始化时需要创建配置索引
+    createConfIndex();
+
+    /**
+     * paths内部索引
+     *
+     * @inner
+     * @type {Array}
+     */
+    var pathsIndex;
+
+    /**
+     * packages内部索引
+     *
+     * @inner
+     * @type {Array}
+     */
+    var packagesIndex;
+
+    /**
+     * mapping内部索引
+     *
+     * @inner
+     * @type {Array}
+     */
+    var mappingIdIndex;
+
+    /**
+     * bundles内部索引
+     *
+     * @inner
+     * @type {Object}
+     */
+    var bundlesIndex;
+
+    /**
+     * urlArgs内部索引
+     *
+     * @inner
+     * @type {Array}
+     */
+    var urlArgsIndex;
+
+    /**
+     * 将key为module id prefix的Object,生成数组形式的索引,并按照长度和字面排序
+     *
+     * @inner
+     * @param {Object} value 源值
+     * @param {boolean} allowAsterisk 是否允许*号表示匹配所有
+     * @return {Array} 索引对象
+     */
+    function createKVSortedIndex(value, allowAsterisk) {
+        var index = kv2List(value, 1, allowAsterisk);
+        index.sort(descSorterByKOrName);
+        return index;
+    }
+
+    /**
+     * 创建配置信息内部索引
+     *
+     * @inner
+     */
+    function createConfIndex() {
+        requireConf.baseUrl = requireConf.baseUrl.replace(/\/$/, '') + '/';
+
+        // create paths index
+        pathsIndex = createKVSortedIndex(requireConf.paths);
+
+        // create mappingId index
+        mappingIdIndex = createKVSortedIndex(requireConf.map, 1);
+        each(
+            mappingIdIndex,
+            function (item) {
+                item.v = createKVSortedIndex(item.v);
+            }
+        );
+
+        // create packages index
+        packagesIndex = [];
+        each(
+            requireConf.packages,
+            function (packageConf) {
+                var pkg = packageConf;
+                if (typeof packageConf === 'string') {
+                    pkg = {
+                        name: packageConf.split('/')[0],
+                        location: packageConf,
+                        main: 'main'
+                    };
+                }
+
+                pkg.location = pkg.location || pkg.name;
+                pkg.main = (pkg.main || 'main').replace(/\.js$/i, '');
+                pkg.reg = createPrefixRegexp(pkg.name);
+                packagesIndex.push(pkg);
+            }
+        );
+        packagesIndex.sort(descSorterByKOrName);
+
+        // create urlArgs index
+        urlArgsIndex = createKVSortedIndex(requireConf.urlArgs, 1);
+
+        // create bundles index
+        bundlesIndex = {};
+        /* eslint-disable no-use-before-define */
+        function bundlesIterator(id) {
+            bundlesIndex[resolvePackageId(id)] = key;
+        }
+        /* eslint-enable no-use-before-define */
+        for (var key in requireConf.bundles) {
+            each(requireConf.bundles[key], bundlesIterator);
+        }
+    }
+
+    /**
+     * 对配置信息的索引进行检索
+     *
+     * @inner
+     * @param {string} value 要检索的值
+     * @param {Array} index 索引对象
+     * @param {Function} hitBehavior 索引命中的行为函数
+     */
+    function indexRetrieve(value, index, hitBehavior) {
+        each(index, function (item) {
+            if (item.reg.test(value)) {
+                hitBehavior(item.v, item.k, item);
+                return false;
+            }
+        });
+    }
+
+    /**
+     * 将`模块标识+'.extension'`形式的字符串转换成相对的url
+     *
+     * @inner
+     * @param {string} source 源字符串
+     * @return {string} url
+     */
+    function toUrl(source) {
+        // 分离 模块标识 和 .extension
+        var extReg = /(\.[a-z0-9]+)$/i;
+        var queryReg = /(\?[^#]*)$/;
+        var extname = '';
+        var id = source;
+        var query = '';
+
+        if (queryReg.test(source)) {
+            query = RegExp.$1;
+            source = source.replace(queryReg, '');
+        }
+
+        if (extReg.test(source)) {
+            extname = RegExp.$1;
+            id = source.replace(extReg, '');
+        }
+
+        var url = id;
+
+        // paths处理和匹配
+        var isPathMap;
+        indexRetrieve(id, pathsIndex, function (value, key) {
+            url = url.replace(key, value);
+            isPathMap = 1;
+        });
+
+        // packages处理和匹配
+        if (!isPathMap) {
+            indexRetrieve(id, packagesIndex, function (value, key, item) {
+                url = url.replace(item.name, item.location);
+            });
+        }
+
+        // 相对路径时,附加baseUrl
+        if (!/^([a-z]{2,10}:\/)?\//i.test(url)) {
+            url = requireConf.baseUrl + url;
+        }
+
+        // 附加 .extension 和 query
+        url += extname + query;
+
+        // urlArgs处理和匹配
+        indexRetrieve(id, urlArgsIndex, function (value) {
+            url += (url.indexOf('?') > 0 ? '&' : '?') + value;
+        });
+
+        return url;
+    }
+
+    /**
+     * 创建local require函数
+     *
+     * @inner
+     * @param {number} baseId 当前module id
+     * @return {Function} local require函数
+     */
+    function createLocalRequire(baseId) {
+        var requiredCache = {};
+
+        function req(requireId, callback) {
+            if (typeof requireId === 'string') {
+                if (!requiredCache[requireId]) {
+                    var topLevelId = normalize(requireId, baseId);
+
+                    // 根据 https://github.com/amdjs/amdjs-api/wiki/require
+                    // It MUST throw an error if the module has not
+                    // already been loaded and evaluated.
+                    modTryInvokeFactory(topLevelId);
+                    if (!modIs(topLevelId, MODULE_DEFINED)) {
+                        throw new Error('[MODULE_MISS]"' + topLevelId + '" is not exists!');
+                    }
+
+                    requiredCache[requireId] = modModules[topLevelId].exports;
+                }
+
+                return requiredCache[requireId];
+            }
+            else if (requireId instanceof Array) {
+                // 分析是否有resource,取出pluginModule先
+                var pureModules = [];
+                var normalizedIds = [];
+
+                each(
+                    requireId,
+                    function (id, i) {
+                        var idInfo = parseId(id);
+                        var absId = normalize(idInfo.mod, baseId);
+                        var resId = idInfo.res;
+                        var normalizedId = absId;
+
+                        if (resId) {
+                            var trueResId = absId + '!' + resId;
+                            if (resId.indexOf('.') !== 0 && bundlesIndex[trueResId]) {
+                                absId = normalizedId = trueResId;
+                            }
+                            else {
+                                normalizedId = null;
+                            }
+                        }
+
+                        normalizedIds[i] = normalizedId;
+                        modFlagAutoDefine(absId);
+                        pureModules.push(absId);
+                    }
+                );
+
+                // 加载模块
+                nativeAsyncRequire(
+                    pureModules,
+                    function () {
+                        /* jshint ignore:start */
+                        each(normalizedIds, function (id, i) {
+                            if (id == null) {
+                                id = normalizedIds[i] = normalize(requireId[i], baseId);
+                                modFlagAutoDefine(id);
+                            }
+                        });
+                        /* jshint ignore:end */
+
+                        // modAutoDefine中,factory invoke可能发生错误
+                        // 从而导致nativeAsyncRequire没有被调用,callback没挂上
+                        // 所以nativeAsyncRequire要先运行
+                        nativeAsyncRequire(normalizedIds, callback, baseId);
+                        modAutoDefine();
+                    },
+                    baseId
+                );
+                modAutoDefine();
+            }
+        }
+
+        /**
+         * 将[module ID] + '.extension'格式的字符串转换成url
+         *
+         * @inner
+         * @param {string} id 符合描述格式的源字符串
+         * @return {string} url
+         */
+        req.toUrl = function (id) {
+            return toUrl(normalize(id, baseId));
+        };
+
+        return req;
+    }
+
+    /**
+     * id normalize化
+     *
+     * @inner
+     * @param {string} id 需要normalize的模块标识
+     * @param {string} baseId 当前环境的模块标识
+     * @return {string} normalize结果
+     */
+    function normalize(id, baseId) {
+        if (!id) {
+            return '';
+        }
+
+        baseId = baseId || '';
+        var idInfo = parseId(id);
+        if (!idInfo) {
+            return id;
+        }
+
+        var resourceId = idInfo.res;
+        var moduleId = resolvePackageId(
+            relative2absolute(idInfo.mod, baseId)
+        );
+
+        // 根据config中的map配置进行module id mapping
+        indexRetrieve(
+            baseId,
+            mappingIdIndex,
+            function (value) {
+                indexRetrieve(
+                    moduleId,
+                    value,
+                    function (mdValue, mdKey) {
+                        moduleId = moduleId.replace(mdKey, mdValue);
+                    }
+                );
+            }
+        );
+
+        if (resourceId) {
+            var mod = modIs(moduleId, MODULE_DEFINED) && actualGlobalRequire(moduleId);
+            resourceId = mod && mod.normalize
+                ? mod.normalize(
+                    resourceId,
+                    function (resId) {
+                        return normalize(resId, baseId);
+                    }
+                  )
+                : normalize(resourceId, baseId);
+
+            moduleId += '!' + resourceId;
+        }
+
+        return moduleId;
+    }
+
+    /**
+     * 对id进行package解析
+     * 如果是package,则附加主模块id
+     *
+     * @inner
+     * @param {string} id 模块id
+     * @return {string} 解析后的id
+     */
+    function resolvePackageId(id) {
+        each(
+            packagesIndex,
+            function (packageConf) {
+                var name = packageConf.name;
+                if (name === id) {
+                    id = name + '/' + packageConf.main;
+                    return false;
+                }
+            }
+        );
+
+        return id;
+    }
+
+    /**
+     * 相对id转换成绝对id
+     *
+     * @inner
+     * @param {string} id 要转换的相对id
+     * @param {string} baseId 当前所在环境id
+     * @return {string} 绝对id
+     */
+    function relative2absolute(id, baseId) {
+        if (id.indexOf('.') === 0) {
+            var basePath = baseId.split('/');
+            var namePath = id.split('/');
+            var baseLen = basePath.length - 1;
+            var nameLen = namePath.length;
+            var cutBaseTerms = 0;
+            var cutNameTerms = 0;
+
+            /* eslint-disable block-scoped-var */
+            pathLoop: for (var i = 0; i < nameLen; i++) {
+                switch (namePath[i]) {
+                    case '..':
+                        if (cutBaseTerms < baseLen) {
+                            cutBaseTerms++;
+                            cutNameTerms++;
+                        }
+                        else {
+                            break pathLoop;
+                        }
+                        break;
+                    case '.':
+                        cutNameTerms++;
+                        break;
+                    default:
+                        break pathLoop;
+                }
+            }
+            /* eslint-enable block-scoped-var */
+
+            basePath.length = baseLen - cutBaseTerms;
+            namePath = namePath.slice(cutNameTerms);
+
+            return basePath.concat(namePath).join('/');
+        }
+
+        return id;
+    }
+
+    /**
+     * 解析id,返回带有module和resource属性的Object
+     *
+     * @inner
+     * @param {string} id 标识
+     * @return {Object} id解析结果对象
+     */
+    function parseId(id) {
+        var segs = id.split('!');
+
+        if (segs[0]) {
+            return {
+                mod: segs[0],
+                res: segs[1]
+            };
+        }
+    }
+
+    /**
+     * 将对象数据转换成数组,数组每项是带有k和v的Object
+     *
+     * @inner
+     * @param {Object} source 对象数据
+     * @param {boolean} keyMatchable key是否允许被前缀匹配
+     * @param {boolean} allowAsterisk 是否支持*匹配所有
+     * @return {Array.<Object>} 对象转换数组
+     */
+    function kv2List(source, keyMatchable, allowAsterisk) {
+        var list = [];
+        for (var key in source) {
+            if (source.hasOwnProperty(key)) {
+                var item = {
+                    k: key,
+                    v: source[key]
+                };
+                list.push(item);
+
+                if (keyMatchable) {
+                    item.reg = key === '*' && allowAsterisk
+                        ? /^/
+                        : createPrefixRegexp(key);
+                }
+            }
+        }
+
+        return list;
+    }
+
+    // 感谢requirejs,通过currentlyAddingScript兼容老旧ie
+    //
+    // For some cache cases in IE 6-8, the script executes before the end
+    // of the appendChild execution, so to tie an anonymous define
+    // call to the module name (which is stored on the node), hold on
+    // to a reference to this node, but clear after the DOM insertion.
+    var currentlyAddingScript;
+    var interactiveScript;
+
+    /**
+     * 获取当前script标签
+     * 用于ie下define未指定module id时获取id
+     *
+     * @inner
+     * @return {HTMLScriptElement} 当前script标签
+     */
+    function getCurrentScript() {
+        if (currentlyAddingScript) {
+            return currentlyAddingScript;
+        }
+        else if (
+            interactiveScript
+            && interactiveScript.readyState === 'interactive'
+        ) {
+            return interactiveScript;
+        }
+
+        var scripts = document.getElementsByTagName('script');
+        var scriptLen = scripts.length;
+        while (scriptLen--) {
+            var script = scripts[scriptLen];
+            if (script.readyState === 'interactive') {
+                interactiveScript = script;
+                return script;
+            }
+        }
+    }
+
+    var headElement = document.getElementsByTagName('head')[0];
+    var baseElement = document.getElementsByTagName('base')[0];
+    if (baseElement) {
+        headElement = baseElement.parentNode;
+    }
+
+    function createScript(moduleId, onload) {
+        // 创建script标签
+        //
+        // 这里不挂接onerror的错误处理
+        // 因为高级浏览器在devtool的console面板会报错
+        // 再throw一个Error多此一举了
+        var script = document.createElement('script');
+        script.setAttribute('data-require-id', moduleId);
+        script.src = toUrl(moduleId + '.js');
+        script.async = true;
+        if (script.readyState) {
+            script.onreadystatechange = innerOnload;
+        }
+        else {
+            script.onload = innerOnload;
+        }
+
+        function innerOnload() {
+            var readyState = script.readyState;
+            if (
+                typeof readyState === 'undefined'
+                || /^(loaded|complete)$/.test(readyState)
+            ) {
+                script.onload = script.onreadystatechange = null;
+                script = null;
+
+                // Script onload hooker
+                // ECHARTS-BUILDER-WEB
+                esl.onModuleLoad && esl.onModuleLoad(moduleId);
+
+                onload();
+            }
+        }
+        currentlyAddingScript = script;
+
+        // If BASE tag is in play, using appendChild is a problem for IE6.
+        // See: http://dev.jquery.com/ticket/2709
+        baseElement
+            ? headElement.insertBefore(script, baseElement)
+            : headElement.appendChild(script);
+
+        currentlyAddingScript = null;
+
+    }
+
+    /**
+     * 创建id前缀匹配的正则对象
+     *
+     * @inner
+     * @param {string} prefix id前缀
+     * @return {RegExp} 前缀匹配的正则对象
+     */
+    function createPrefixRegexp(prefix) {
+        return new RegExp('^' + prefix + '(/|$)');
+    }
+
+    /**
+     * 循环遍历数组集合
+     *
+     * @inner
+     * @param {Array} source 数组源
+     * @param {function(Array,Number):boolean} iterator 遍历函数
+     */
+    function each(source, iterator) {
+        if (source instanceof Array) {
+            for (var i = 0, len = source.length; i < len; i++) {
+                if (iterator(source[i], i) === false) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * 根据元素的k或name项进行数组字符数逆序的排序函数
+     *
+     * @inner
+     * @param {Object} a 要比较的对象a
+     * @param {Object} b 要比较的对象b
+     * @return {number} 比较结果
+     */
+    function descSorterByKOrName(a, b) {
+        var aValue = a.k || a.name;
+        var bValue = b.k || b.name;
+
+        if (bValue === '*') {
+            return -1;
+        }
+
+        if (aValue === '*') {
+            return 1;
+        }
+
+        return bValue.length - aValue.length;
+    }
+
+    // 暴露全局对象
+    if (!define) {
+        define = globalDefine;
+
+        // 可能碰到其他形式的loader,所以,不要覆盖人家
+        if (!require) {
+            require = globalRequire;
+        }
+
+        // 如果存在其他版本的esl,在define那里就判断过了,不会进入这个分支
+        // 所以这里就不判断了,直接写
+        esl = globalRequire;
+
+        // 为 echarts-builder-web 暴露模块
+        // ECHARTS-BUILDER-WEB
+        esl.modules = modModules;
+    }
+})(this);
\ No newline at end of file
diff --git a/builder/lib/esprima.js b/builder/lib/esprima.js
new file mode 100644
index 0000000..654e5fd
--- /dev/null
+++ b/builder/lib/esprima.js
@@ -0,0 +1,5739 @@
+/*
+  Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+(function (root, factory) {
+    'use strict';
+
+    // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
+    // Rhino, and plain browser loading.
+
+    /* istanbul ignore next */
+    if (typeof define === 'function' && define.amd) {
+        define(['exports'], factory);
+    } else if (typeof exports !== 'undefined') {
+        factory(exports);
+    } else {
+        factory((root.esprima = {}));
+    }
+}(this, function (exports) {
+    'use strict';
+
+    var Token,
+        TokenName,
+        FnExprTokens,
+        Syntax,
+        PlaceHolders,
+        Messages,
+        Regex,
+        source,
+        strict,
+        index,
+        lineNumber,
+        lineStart,
+        hasLineTerminator,
+        lastIndex,
+        lastLineNumber,
+        lastLineStart,
+        startIndex,
+        startLineNumber,
+        startLineStart,
+        scanning,
+        length,
+        lookahead,
+        state,
+        extra,
+        isBindingElement,
+        isAssignmentTarget,
+        firstCoverInitializedNameError;
+
+    Token = {
+        BooleanLiteral: 1,
+        EOF: 2,
+        Identifier: 3,
+        Keyword: 4,
+        NullLiteral: 5,
+        NumericLiteral: 6,
+        Punctuator: 7,
+        StringLiteral: 8,
+        RegularExpression: 9,
+        Template: 10
+    };
+
+    TokenName = {};
+    TokenName[Token.BooleanLiteral] = 'Boolean';
+    TokenName[Token.EOF] = '<end>';
+    TokenName[Token.Identifier] = 'Identifier';
+    TokenName[Token.Keyword] = 'Keyword';
+    TokenName[Token.NullLiteral] = 'Null';
+    TokenName[Token.NumericLiteral] = 'Numeric';
+    TokenName[Token.Punctuator] = 'Punctuator';
+    TokenName[Token.StringLiteral] = 'String';
+    TokenName[Token.RegularExpression] = 'RegularExpression';
+    TokenName[Token.Template] = 'Template';
+
+    // A function following one of those tokens is an expression.
+    FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
+                    'return', 'case', 'delete', 'throw', 'void',
+                    // assignment operators
+                    '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
+                    '&=', '|=', '^=', ',',
+                    // binary/unary operators
+                    '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
+                    '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
+                    '<=', '<', '>', '!=', '!=='];
+
+    Syntax = {
+        AssignmentExpression: 'AssignmentExpression',
+        AssignmentPattern: 'AssignmentPattern',
+        ArrayExpression: 'ArrayExpression',
+        ArrayPattern: 'ArrayPattern',
+        ArrowFunctionExpression: 'ArrowFunctionExpression',
+        BlockStatement: 'BlockStatement',
+        BinaryExpression: 'BinaryExpression',
+        BreakStatement: 'BreakStatement',
+        CallExpression: 'CallExpression',
+        CatchClause: 'CatchClause',
+        ClassBody: 'ClassBody',
+        ClassDeclaration: 'ClassDeclaration',
+        ClassExpression: 'ClassExpression',
+        ConditionalExpression: 'ConditionalExpression',
+        ContinueStatement: 'ContinueStatement',
+        DoWhileStatement: 'DoWhileStatement',
+        DebuggerStatement: 'DebuggerStatement',
+        EmptyStatement: 'EmptyStatement',
+        ExportAllDeclaration: 'ExportAllDeclaration',
+        ExportDefaultDeclaration: 'ExportDefaultDeclaration',
+        ExportNamedDeclaration: 'ExportNamedDeclaration',
+        ExportSpecifier: 'ExportSpecifier',
+        ExpressionStatement: 'ExpressionStatement',
+        ForStatement: 'ForStatement',
+        ForOfStatement: 'ForOfStatement',
+        ForInStatement: 'ForInStatement',
+        FunctionDeclaration: 'FunctionDeclaration',
+        FunctionExpression: 'FunctionExpression',
+        Identifier: 'Identifier',
+        IfStatement: 'IfStatement',
+        ImportDeclaration: 'ImportDeclaration',
+        ImportDefaultSpecifier: 'ImportDefaultSpecifier',
+        ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
+        ImportSpecifier: 'ImportSpecifier',
+        Literal: 'Literal',
+        LabeledStatement: 'LabeledStatement',
+        LogicalExpression: 'LogicalExpression',
+        MemberExpression: 'MemberExpression',
+        MetaProperty: 'MetaProperty',
+        MethodDefinition: 'MethodDefinition',
+        NewExpression: 'NewExpression',
+        ObjectExpression: 'ObjectExpression',
+        ObjectPattern: 'ObjectPattern',
+        Program: 'Program',
+        Property: 'Property',
+        RestElement: 'RestElement',
+        ReturnStatement: 'ReturnStatement',
+        SequenceExpression: 'SequenceExpression',
+        SpreadElement: 'SpreadElement',
+        Super: 'Super',
+        SwitchCase: 'SwitchCase',
+        SwitchStatement: 'SwitchStatement',
+        TaggedTemplateExpression: 'TaggedTemplateExpression',
+        TemplateElement: 'TemplateElement',
+        TemplateLiteral: 'TemplateLiteral',
+        ThisExpression: 'ThisExpression',
+        ThrowStatement: 'ThrowStatement',
+        TryStatement: 'TryStatement',
+        UnaryExpression: 'UnaryExpression',
+        UpdateExpression: 'UpdateExpression',
+        VariableDeclaration: 'VariableDeclaration',
+        VariableDeclarator: 'VariableDeclarator',
+        WhileStatement: 'WhileStatement',
+        WithStatement: 'WithStatement',
+        YieldExpression: 'YieldExpression'
+    };
+
+    PlaceHolders = {
+        ArrowParameterPlaceHolder: 'ArrowParameterPlaceHolder'
+    };
+
+    // Error messages should be identical to V8.
+    Messages = {
+        UnexpectedToken: 'Unexpected token %0',
+        UnexpectedNumber: 'Unexpected number',
+        UnexpectedString: 'Unexpected string',
+        UnexpectedIdentifier: 'Unexpected identifier',
+        UnexpectedReserved: 'Unexpected reserved word',
+        UnexpectedTemplate: 'Unexpected quasi %0',
+        UnexpectedEOS: 'Unexpected end of input',
+        NewlineAfterThrow: 'Illegal newline after throw',
+        InvalidRegExp: 'Invalid regular expression',
+        UnterminatedRegExp: 'Invalid regular expression: missing /',
+        InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
+        InvalidLHSInForIn: 'Invalid left-hand side in for-in',
+        InvalidLHSInForLoop: 'Invalid left-hand side in for-loop',
+        MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
+        NoCatchOrFinally: 'Missing catch or finally after try',
+        UnknownLabel: 'Undefined label \'%0\'',
+        Redeclaration: '%0 \'%1\' has already been declared',
+        IllegalContinue: 'Illegal continue statement',
+        IllegalBreak: 'Illegal break statement',
+        IllegalReturn: 'Illegal return statement',
+        StrictModeWith: 'Strict mode code may not include a with statement',
+        StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
+        StrictVarName: 'Variable name may not be eval or arguments in strict mode',
+        StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
+        StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
+        StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
+        StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
+        StrictDelete: 'Delete of an unqualified identifier in strict mode.',
+        StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
+        StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
+        StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
+        StrictReservedWord: 'Use of future reserved word in strict mode',
+        TemplateOctalLiteral: 'Octal literals are not allowed in template strings.',
+        ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
+        DefaultRestParameter: 'Unexpected token =',
+        ObjectPatternAsRestParameter: 'Unexpected token {',
+        DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
+        ConstructorSpecialMethod: 'Class constructor may not be an accessor',
+        DuplicateConstructor: 'A class may only have one constructor',
+        StaticPrototype: 'Classes may not have static property named prototype',
+        MissingFromClause: 'Unexpected token',
+        NoAsAfterImportNamespace: 'Unexpected token',
+        InvalidModuleSpecifier: 'Unexpected token',
+        IllegalImportDeclaration: 'Unexpected token',
+        IllegalExportDeclaration: 'Unexpected token',
+        DuplicateBinding: 'Duplicate binding %0'
+    };
+
+    // See also tools/generate-unicode-regex.js.
+    Regex = {
+        // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierStart:
+        NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u085 [...]
+
+        // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierPart:
+        NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u08 [...]
+    };
+
+    // Ensure the condition is true, otherwise throw an error.
+    // This is only to have a better contract semantic, i.e. another safety net
+    // to catch a logic error. The condition shall be fulfilled in normal case.
+    // Do NOT use this to enforce a certain condition on any user input.
+
+    function assert(condition, message) {
+        /* istanbul ignore if */
+        if (!condition) {
+            throw new Error('ASSERT: ' + message);
+        }
+    }
+
+    function isDecimalDigit(ch) {
+        return (ch >= 0x30 && ch <= 0x39);   // 0..9
+    }
+
+    function isHexDigit(ch) {
+        return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
+    }
+
+    function isOctalDigit(ch) {
+        return '01234567'.indexOf(ch) >= 0;
+    }
+
+    function octalToDecimal(ch) {
+        // \0 is not octal escape sequence
+        var octal = (ch !== '0'), code = '01234567'.indexOf(ch);
+
+        if (index < length && isOctalDigit(source[index])) {
+            octal = true;
+            code = code * 8 + '01234567'.indexOf(source[index++]);
+
+            // 3 digits are only allowed when string starts
+            // with 0, 1, 2, 3
+            if ('0123'.indexOf(ch) >= 0 &&
+                    index < length &&
+                    isOctalDigit(source[index])) {
+                code = code * 8 + '01234567'.indexOf(source[index++]);
+            }
+        }
+
+        return {
+            code: code,
+            octal: octal
+        };
+    }
+
+    // ECMA-262 11.2 White Space
+
+    function isWhiteSpace(ch) {
+        return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
+            (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
+    }
+
+    // ECMA-262 11.3 Line Terminators
+
+    function isLineTerminator(ch) {
+        return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
+    }
+
+    // ECMA-262 11.6 Identifier Names and Identifiers
+
+    function fromCodePoint(cp) {
+        return (cp < 0x10000) ? String.fromCharCode(cp) :
+            String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) +
+            String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023));
+    }
+
+    function isIdentifierStart(ch) {
+        return (ch === 0x24) || (ch === 0x5F) ||  // $ (dollar) and _ (underscore)
+            (ch >= 0x41 && ch <= 0x5A) ||         // A..Z
+            (ch >= 0x61 && ch <= 0x7A) ||         // a..z
+            (ch === 0x5C) ||                      // \ (backslash)
+            ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(fromCodePoint(ch)));
+    }
+
+    function isIdentifierPart(ch) {
+        return (ch === 0x24) || (ch === 0x5F) ||  // $ (dollar) and _ (underscore)
+            (ch >= 0x41 && ch <= 0x5A) ||         // A..Z
+            (ch >= 0x61 && ch <= 0x7A) ||         // a..z
+            (ch >= 0x30 && ch <= 0x39) ||         // 0..9
+            (ch === 0x5C) ||                      // \ (backslash)
+            ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(fromCodePoint(ch)));
+    }
+
+    // ECMA-262 11.6.2.2 Future Reserved Words
+
+    function isFutureReservedWord(id) {
+        switch (id) {
+        case 'enum':
+        case 'export':
+        case 'import':
+        case 'super':
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    function isStrictModeReservedWord(id) {
+        switch (id) {
+        case 'implements':
+        case 'interface':
+        case 'package':
+        case 'private':
+        case 'protected':
+        case 'public':
+        case 'static':
+        case 'yield':
+        case 'let':
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    function isRestrictedWord(id) {
+        return id === 'eval' || id === 'arguments';
+    }
+
+    // ECMA-262 11.6.2.1 Keywords
+
+    function isKeyword(id) {
+        switch (id.length) {
+        case 2:
+            return (id === 'if') || (id === 'in') || (id === 'do');
+        case 3:
+            return (id === 'var') || (id === 'for') || (id === 'new') ||
+                (id === 'try') || (id === 'let');
+        case 4:
+            return (id === 'this') || (id === 'else') || (id === 'case') ||
+                (id === 'void') || (id === 'with') || (id === 'enum');
+        case 5:
+            return (id === 'while') || (id === 'break') || (id === 'catch') ||
+                (id === 'throw') || (id === 'const') || (id === 'yield') ||
+                (id === 'class') || (id === 'super');
+        case 6:
+            return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
+                (id === 'switch') || (id === 'export') || (id === 'import');
+        case 7:
+            return (id === 'default') || (id === 'finally') || (id === 'extends');
+        case 8:
+            return (id === 'function') || (id === 'continue') || (id === 'debugger');
+        case 10:
+            return (id === 'instanceof');
+        default:
+            return false;
+        }
+    }
+
+    // ECMA-262 11.4 Comments
+
+    function addComment(type, value, start, end, loc) {
+        var comment;
+
+        assert(typeof start === 'number', 'Comment must have valid position');
+
+        state.lastCommentStart = start;
+
+        comment = {
+            type: type,
+            value: value
+        };
+        if (extra.range) {
+            comment.range = [start, end];
+        }
+        if (extra.loc) {
+            comment.loc = loc;
+        }
+        extra.comments.push(comment);
+        if (extra.attachComment) {
+            extra.leadingComments.push(comment);
+            extra.trailingComments.push(comment);
+        }
+        if (extra.tokenize) {
+            comment.type = comment.type + 'Comment';
+            if (extra.delegate) {
+                comment = extra.delegate(comment);
+            }
+            extra.tokens.push(comment);
+        }
+    }
+
+    function skipSingleLineComment(offset) {
+        var start, loc, ch, comment;
+
+        start = index - offset;
+        loc = {
+            start: {
+                line: lineNumber,
+                column: index - lineStart - offset
+            }
+        };
+
+        while (index < length) {
+            ch = source.charCodeAt(index);
+            ++index;
+            if (isLineTerminator(ch)) {
+                hasLineTerminator = true;
+                if (extra.comments) {
+                    comment = source.slice(start + offset, index - 1);
+                    loc.end = {
+                        line: lineNumber,
+                        column: index - lineStart - 1
+                    };
+                    addComment('Line', comment, start, index - 1, loc);
+                }
+                if (ch === 13 && source.charCodeAt(index) === 10) {
+                    ++index;
+                }
+                ++lineNumber;
+                lineStart = index;
+                return;
+            }
+        }
+
+        if (extra.comments) {
+            comment = source.slice(start + offset, index);
+            loc.end = {
+                line: lineNumber,
+                column: index - lineStart
+            };
+            addComment('Line', comment, start, index, loc);
+        }
+    }
+
+    function skipMultiLineComment() {
+        var start, loc, ch, comment;
+
+        if (extra.comments) {
+            start = index - 2;
+            loc = {
+                start: {
+                    line: lineNumber,
+                    column: index - lineStart - 2
+                }
+            };
+        }
+
+        while (index < length) {
+            ch = source.charCodeAt(index);
+            if (isLineTerminator(ch)) {
+                if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
+                    ++index;
+                }
+                hasLineTerminator = true;
+                ++lineNumber;
+                ++index;
+                lineStart = index;
+            } else if (ch === 0x2A) {
+                // Block comment ends with '*/'.
+                if (source.charCodeAt(index + 1) === 0x2F) {
+                    ++index;
+                    ++index;
+                    if (extra.comments) {
+                        comment = source.slice(start + 2, index - 2);
+                        loc.end = {
+                            line: lineNumber,
+                            column: index - lineStart
+                        };
+                        addComment('Block', comment, start, index, loc);
+                    }
+                    return;
+                }
+                ++index;
+            } else {
+                ++index;
+            }
+        }
+
+        // Ran off the end of the file - the whole thing is a comment
+        if (extra.comments) {
+            loc.end = {
+                line: lineNumber,
+                column: index - lineStart
+            };
+            comment = source.slice(start + 2, index);
+            addComment('Block', comment, start, index, loc);
+        }
+        tolerateUnexpectedToken();
+    }
+
+    function skipComment() {
+        var ch, start;
+        hasLineTerminator = false;
+
+        start = (index === 0);
+        while (index < length) {
+            ch = source.charCodeAt(index);
+
+            if (isWhiteSpace(ch)) {
+                ++index;
+            } else if (isLineTerminator(ch)) {
+                hasLineTerminator = true;
+                ++index;
+                if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
+                    ++index;
+                }
+                ++lineNumber;
+                lineStart = index;
+                start = true;
+            } else if (ch === 0x2F) { // U+002F is '/'
+                ch = source.charCodeAt(index + 1);
+                if (ch === 0x2F) {
+                    ++index;
+                    ++index;
+                    skipSingleLineComment(2);
+                    start = true;
+                } else if (ch === 0x2A) {  // U+002A is '*'
+                    ++index;
+                    ++index;
+                    skipMultiLineComment();
+                } else {
+                    break;
+                }
+            } else if (start && ch === 0x2D) { // U+002D is '-'
+                // U+003E is '>'
+                if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
+                    // '-->' is a single-line comment
+                    index += 3;
+                    skipSingleLineComment(3);
+                } else {
+                    break;
+                }
+            } else if (ch === 0x3C) { // U+003C is '<'
+                if (source.slice(index + 1, index + 4) === '!--') {
+                    ++index; // `<`
+                    ++index; // `!`
+                    ++index; // `-`
+                    ++index; // `-`
+                    skipSingleLineComment(4);
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        }
+    }
+
+    function scanHexEscape(prefix) {
+        var i, len, ch, code = 0;
+
+        len = (prefix === 'u') ? 4 : 2;
+        for (i = 0; i < len; ++i) {
+            if (index < length && isHexDigit(source[index])) {
+                ch = source[index++];
+                code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+            } else {
+                return '';
+            }
+        }
+        return String.fromCharCode(code);
+    }
+
+    function scanUnicodeCodePointEscape() {
+        var ch, code;
+
+        ch = source[index];
+        code = 0;
+
+        // At least, one hex digit is required.
+        if (ch === '}') {
+            throwUnexpectedToken();
+        }
+
+        while (index < length) {
+            ch = source[index++];
+            if (!isHexDigit(ch)) {
+                break;
+            }
+            code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+        }
+
+        if (code > 0x10FFFF || ch !== '}') {
+            throwUnexpectedToken();
+        }
+
+        return fromCodePoint(code);
+    }
+
+    function codePointAt(i) {
+        var cp, first, second;
+
+        cp = source.charCodeAt(i);
+        if (cp >= 0xD800 && cp <= 0xDBFF) {
+            second = source.charCodeAt(i + 1);
+            if (second >= 0xDC00 && second <= 0xDFFF) {
+                first = cp;
+                cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
+            }
+        }
+
+        return cp;
+    }
+
+    function getComplexIdentifier() {
+        var cp, ch, id;
+
+        cp = codePointAt(index);
+        id = fromCodePoint(cp);
+        index += id.length;
+
+        // '\u' (U+005C, U+0075) denotes an escaped character.
+        if (cp === 0x5C) {
+            if (source.charCodeAt(index) !== 0x75) {
+                throwUnexpectedToken();
+            }
+            ++index;
+            if (source[index] === '{') {
+                ++index;
+                ch = scanUnicodeCodePointEscape();
+            } else {
+                ch = scanHexEscape('u');
+                cp = ch.charCodeAt(0);
+                if (!ch || ch === '\\' || !isIdentifierStart(cp)) {
+                    throwUnexpectedToken();
+                }
+            }
+            id = ch;
+        }
+
+        while (index < length) {
+            cp = codePointAt(index);
+            if (!isIdentifierPart(cp)) {
+                break;
+            }
+            ch = fromCodePoint(cp);
+            id += ch;
+            index += ch.length;
+
+            // '\u' (U+005C, U+0075) denotes an escaped character.
+            if (cp === 0x5C) {
+                id = id.substr(0, id.length - 1);
+                if (source.charCodeAt(index) !== 0x75) {
+                    throwUnexpectedToken();
+                }
+                ++index;
+                if (source[index] === '{') {
+                    ++index;
+                    ch = scanUnicodeCodePointEscape();
+                } else {
+                    ch = scanHexEscape('u');
+                    cp = ch.charCodeAt(0);
+                    if (!ch || ch === '\\' || !isIdentifierPart(cp)) {
+                        throwUnexpectedToken();
+                    }
+                }
+                id += ch;
+            }
+        }
+
+        return id;
+    }
+
+    function getIdentifier() {
+        var start, ch;
+
+        start = index++;
+        while (index < length) {
+            ch = source.charCodeAt(index);
+            if (ch === 0x5C) {
+                // Blackslash (U+005C) marks Unicode escape sequence.
+                index = start;
+                return getComplexIdentifier();
+            } else if (ch >= 0xD800 && ch < 0xDFFF) {
+                // Need to handle surrogate pairs.
+                index = start;
+                return getComplexIdentifier();
+            }
+            if (isIdentifierPart(ch)) {
+                ++index;
+            } else {
+                break;
+            }
+        }
+
+        return source.slice(start, index);
+    }
+
+    function scanIdentifier() {
+        var start, id, type;
+
+        start = index;
+
+        // Backslash (U+005C) starts an escaped character.
+        id = (source.charCodeAt(index) === 0x5C) ? getComplexIdentifier() : getIdentifier();
+
+        // There is no keyword or literal with only one character.
+        // Thus, it must be an identifier.
+        if (id.length === 1) {
+            type = Token.Identifier;
+        } else if (isKeyword(id)) {
+            type = Token.Keyword;
+        } else if (id === 'null') {
+            type = Token.NullLiteral;
+        } else if (id === 'true' || id === 'false') {
+            type = Token.BooleanLiteral;
+        } else {
+            type = Token.Identifier;
+        }
+
+        return {
+            type: type,
+            value: id,
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            start: start,
+            end: index
+        };
+    }
+
+
+    // ECMA-262 11.7 Punctuators
+
+    function scanPunctuator() {
+        var token, str;
+
+        token = {
+            type: Token.Punctuator,
+            value: '',
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            start: index,
+            end: index
+        };
+
+        // Check for most common single-character punctuators.
+        str = source[index];
+        switch (str) {
+
+        case '(':
+            if (extra.tokenize) {
+                extra.openParenToken = extra.tokenValues.length;
+            }
+            ++index;
+            break;
+
+        case '{':
+            if (extra.tokenize) {
+                extra.openCurlyToken = extra.tokenValues.length;
+            }
+            state.curlyStack.push('{');
+            ++index;
+            break;
+
+        case '.':
+            ++index;
+            if (source[index] === '.' && source[index + 1] === '.') {
+                // Spread operator: ...
+                index += 2;
+                str = '...';
+            }
+            break;
+
+        case '}':
+            ++index;
+            state.curlyStack.pop();
+            break;
+        case ')':
+        case ';':
+        case ',':
+        case '[':
+        case ']':
+        case ':':
+        case '?':
+        case '~':
+            ++index;
+            break;
+
+        default:
+            // 4-character punctuator.
+            str = source.substr(index, 4);
+            if (str === '>>>=') {
+                index += 4;
+            } else {
+
+                // 3-character punctuators.
+                str = str.substr(0, 3);
+                if (str === '===' || str === '!==' || str === '>>>' ||
+                    str === '<<=' || str === '>>=') {
+                    index += 3;
+                } else {
+
+                    // 2-character punctuators.
+                    str = str.substr(0, 2);
+                    if (str === '&&' || str === '||' || str === '==' || str === '!=' ||
+                        str === '+=' || str === '-=' || str === '*=' || str === '/=' ||
+                        str === '++' || str === '--' || str === '<<' || str === '>>' ||
+                        str === '&=' || str === '|=' || str === '^=' || str === '%=' ||
+                        str === '<=' || str === '>=' || str === '=>') {
+                        index += 2;
+                    } else {
+
+                        // 1-character punctuators.
+                        str = source[index];
+                        if ('<>=!+-*%&|^/'.indexOf(str) >= 0) {
+                            ++index;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (index === token.start) {
+            throwUnexpectedToken();
+        }
+
+        token.end = index;
+        token.value = str;
+        return token;
+    }
+
+    // ECMA-262 11.8.3 Numeric Literals
+
+    function scanHexLiteral(start) {
+        var number = '';
+
+        while (index < length) {
+            if (!isHexDigit(source[index])) {
+                break;
+            }
+            number += source[index++];
+        }
+
+        if (number.length === 0) {
+            throwUnexpectedToken();
+        }
+
+        if (isIdentifierStart(source.charCodeAt(index))) {
+            throwUnexpectedToken();
+        }
+
+        return {
+            type: Token.NumericLiteral,
+            value: parseInt('0x' + number, 16),
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            start: start,
+            end: index
+        };
+    }
+
+    function scanBinaryLiteral(start) {
+        var ch, number;
+
+        number = '';
+
+        while (index < length) {
+            ch = source[index];
+            if (ch !== '0' && ch !== '1') {
+                break;
+            }
+            number += source[index++];
+        }
+
+        if (number.length === 0) {
+            // only 0b or 0B
+            throwUnexpectedToken();
+        }
+
+        if (index < length) {
+            ch = source.charCodeAt(index);
+            /* istanbul ignore else */
+            if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+                throwUnexpectedToken();
+            }
+        }
+
+        return {
+            type: Token.NumericLiteral,
+            value: parseInt(number, 2),
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            start: start,
+            end: index
+        };
+    }
+
+    function scanOctalLiteral(prefix, start) {
+        var number, octal;
+
+        if (isOctalDigit(prefix)) {
+            octal = true;
+            number = '0' + source[index++];
+        } else {
+            octal = false;
+            ++index;
+            number = '';
+        }
+
+        while (index < length) {
+            if (!isOctalDigit(source[index])) {
+                break;
+            }
+            number += source[index++];
+        }
+
+        if (!octal && number.length === 0) {
+            // only 0o or 0O
+            throwUnexpectedToken();
+        }
+
+        if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
+            throwUnexpectedToken();
+        }
+
+        return {
+            type: Token.NumericLiteral,
+            value: parseInt(number, 8),
+            octal: octal,
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            start: start,
+            end: index
+        };
+    }
+
+    function isImplicitOctalLiteral() {
+        var i, ch;
+
+        // Implicit octal, unless there is a non-octal digit.
+        // (Annex B.1.1 on Numeric Literals)
+        for (i = index + 1; i < length; ++i) {
+            ch = source[i];
+            if (ch === '8' || ch === '9') {
+                return false;
+            }
+            if (!isOctalDigit(ch)) {
+                return true;
+            }
+        }
+
+        return true;
+    }
+
+    function scanNumericLiteral() {
+        var number, start, ch;
+
+        ch = source[index];
+        assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
+            'Numeric literal must start with a decimal digit or a decimal point');
+
+        start = index;
+        number = '';
+        if (ch !== '.') {
+            number = source[index++];
+            ch = source[index];
+
+            // Hex number starts with '0x'.
+            // Octal number starts with '0'.
+            // Octal number in ES6 starts with '0o'.
+            // Binary number in ES6 starts with '0b'.
+            if (number === '0') {
+                if (ch === 'x' || ch === 'X') {
+                    ++index;
+                    return scanHexLiteral(start);
+                }
+                if (ch === 'b' || ch === 'B') {
+                    ++index;
+                    return scanBinaryLiteral(start);
+                }
+                if (ch === 'o' || ch === 'O') {
+                    return scanOctalLiteral(ch, start);
+                }
+
+                if (isOctalDigit(ch)) {
+                    if (isImplicitOctalLiteral()) {
+                        return scanOctalLiteral(ch, start);
+                    }
+                }
+            }
+
+            while (isDecimalDigit(source.charCodeAt(index))) {
+                number += source[index++];
+            }
+            ch = source[index];
+        }
+
+        if (ch === '.') {
+            number += source[index++];
+            while (isDecimalDigit(source.charCodeAt(index))) {
+                number += source[index++];
+            }
+            ch = source[index];
+        }
+
+        if (ch === 'e' || ch === 'E') {
+            number += source[index++];
+
+            ch = source[index];
+            if (ch === '+' || ch === '-') {
+                number += source[index++];
+            }
+            if (isDecimalDigit(source.charCodeAt(index))) {
+                while (isDecimalDigit(source.charCodeAt(index))) {
+                    number += source[index++];
+                }
+            } else {
+                throwUnexpectedToken();
+            }
+        }
+
+        if (isIdentifierStart(source.charCodeAt(index))) {
+            throwUnexpectedToken();
+        }
+
+        return {
+            type: Token.NumericLiteral,
+            value: parseFloat(number),
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            start: start,
+            end: index
+        };
+    }
+
+    // ECMA-262 11.8.4 String Literals
+
+    function scanStringLiteral() {
+        var str = '', quote, start, ch, unescaped, octToDec, octal = false;
+
+        quote = source[index];
+        assert((quote === '\'' || quote === '"'),
+            'String literal must starts with a quote');
+
+        start = index;
+        ++index;
+
+        while (index < length) {
+            ch = source[index++];
+
+            if (ch === quote) {
+                quote = '';
+                break;
+            } else if (ch === '\\') {
+                ch = source[index++];
+                if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
+                    switch (ch) {
+                    case 'u':
+                    case 'x':
+                        if (source[index] === '{') {
+                            ++index;
+                            str += scanUnicodeCodePointEscape();
+                        } else {
+                            unescaped = scanHexEscape(ch);
+                            if (!unescaped) {
+                                throw throwUnexpectedToken();
+                            }
+                            str += unescaped;
+                        }
+                        break;
+                    case 'n':
+                        str += '\n';
+                        break;
+                    case 'r':
+                        str += '\r';
+                        break;
+                    case 't':
+                        str += '\t';
+                        break;
+                    case 'b':
+                        str += '\b';
+                        break;
+                    case 'f':
+                        str += '\f';
+                        break;
+                    case 'v':
+                        str += '\x0B';
+                        break;
+                    case '8':
+                    case '9':
+                        str += ch;
+                        tolerateUnexpectedToken();
+                        break;
+
+                    default:
+                        if (isOctalDigit(ch)) {
+                            octToDec = octalToDecimal(ch);
+
+                            octal = octToDec.octal || octal;
+                            str += String.fromCharCode(octToDec.code);
+                        } else {
+                            str += ch;
+                        }
+                        break;
+                    }
+                } else {
+                    ++lineNumber;
+                    if (ch === '\r' && source[index] === '\n') {
+                        ++index;
+                    }
+                    lineStart = index;
+                }
+            } else if (isLineTerminator(ch.charCodeAt(0))) {
+                break;
+            } else {
+                str += ch;
+            }
+        }
+
+        if (quote !== '') {
+            index = start;
+            throwUnexpectedToken();
+        }
+
+        return {
+            type: Token.StringLiteral,
+            value: str,
+            octal: octal,
+            lineNumber: startLineNumber,
+            lineStart: startLineStart,
+            start: start,
+            end: index
+        };
+    }
+
+    // ECMA-262 11.8.6 Template Literal Lexical Components
+
+    function scanTemplate() {
+        var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped;
+
+        terminated = false;
+        tail = false;
+        start = index;
+        head = (source[index] === '`');
+        rawOffset = 2;
+
+        ++index;
+
+        while (index < length) {
+            ch = source[index++];
+            if (ch === '`') {
+                rawOffset = 1;
+                tail = true;
+                terminated = true;
+                break;
+            } else if (ch === '$') {
+                if (source[index] === '{') {
+                    state.curlyStack.push('${');
+                    ++index;
+                    terminated = true;
+                    break;
+                }
+                cooked += ch;
+            } else if (ch === '\\') {
+                ch = source[index++];
+                if (!isLineTerminator(ch.charCodeAt(0))) {
+                    switch (ch) {
+                    case 'n':
+                        cooked += '\n';
+                        break;
+                    case 'r':
+                        cooked += '\r';
+                        break;
+                    case 't':
+                        cooked += '\t';
+                        break;
+                    case 'u':
+                    case 'x':
+                        if (source[index] === '{') {
+                            ++index;
+                            cooked += scanUnicodeCodePointEscape();
+                        } else {
+                            restore = index;
+                            unescaped = scanHexEscape(ch);
+                            if (unescaped) {
+                                cooked += unescaped;
+                            } else {
+                                index = restore;
+                                cooked += ch;
+                            }
+                        }
+                        break;
+                    case 'b':
+                        cooked += '\b';
+                        break;
+                    case 'f':
+                        cooked += '\f';
+                        break;
+                    case 'v':
+                        cooked += '\v';
+                        break;
+
+                    default:
+                        if (ch === '0') {
+                            if (isDecimalDigit(source.charCodeAt(index))) {
+                                // Illegal: \01 \02 and so on
+                                throwError(Messages.TemplateOctalLiteral);
+                            }
+                            cooked += '\0';
+                        } else if (isOctalDigit(ch)) {
+                            // Illegal: \1 \2
+                            throwError(Messages.TemplateOctalLiteral);
+                        } else {
+                            cooked += ch;
+                        }
+                        break;
+                    }
+                } else {
+                    ++lineNumber;
+                    if (ch === '\r' && source[index] === '\n') {
+                        ++index;
+                    }
+                    lineStart = index;
+                }
+            } else if (isLineTerminator(ch.charCodeAt(0))) {
+                ++lineNumber;
+                if (ch === '\r' && source[index] === '\n') {
+                    ++index;
+                }
+                lineStart = index;
+                cooked += '\n';
+            } else {
+                cooked += ch;
+            }
+        }
+
+        if (!terminated) {
+            throwUnexpectedToken();
+        }
+
+        if (!head) {
+            state.curlyStack.pop();
+        }
+
+        return {
+            type: Token.Template,
+            value: {
+                cooked: cooked,
+                raw: source.slice(start + 1, index - rawOffset)
+            },
+            head: head,
+            tail: tail,
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            start: start,
+            end: index
+        };
+    }
+
+    // ECMA-262 11.8.5 Regular Expression Literals
+
+    function testRegExp(pattern, flags) {
+        // The BMP character to use as a replacement for astral symbols when
+        // translating an ES6 "u"-flagged pattern to an ES5-compatible
+        // approximation.
+        // Note: replacing with '\uFFFF' enables false positives in unlikely
+        // scenarios. For example, `[\u{1044f}-\u{10440}]` is an invalid
+        // pattern that would not be detected by this substitution.
+        var astralSubstitute = '\uFFFF',
+            tmp = pattern;
+
+        if (flags.indexOf('u') >= 0) {
+            tmp = tmp
+                // Replace every Unicode escape sequence with the equivalent
+                // BMP character or a constant ASCII code point in the case of
+                // astral symbols. (See the above note on `astralSubstitute`
+                // for more information.)
+                .replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g, function ($0, $1, $2) {
+                    var codePoint = parseInt($1 || $2, 16);
+                    if (codePoint > 0x10FFFF) {
+                        throwUnexpectedToken(null, Messages.InvalidRegExp);
+                    }
+                    if (codePoint <= 0xFFFF) {
+                        return String.fromCharCode(codePoint);
+                    }
+                    return astralSubstitute;
+                })
+                // Replace each paired surrogate with a single ASCII symbol to
+                // avoid throwing on regular expressions that are only valid in
+                // combination with the "u" flag.
+                .replace(
+                    /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+                    astralSubstitute
+                );
+        }
+
+        // First, detect invalid regular expressions.
+        try {
+            RegExp(tmp);
+        } catch (e) {
+            throwUnexpectedToken(null, Messages.InvalidRegExp);
+        }
+
+        // Return a regular expression object for this pattern-flag pair, or
+        // `null` in case the current environment doesn't support the flags it
+        // uses.
+        try {
+            return new RegExp(pattern, flags);
+        } catch (exception) {
+            return null;
+        }
+    }
+
+    function scanRegExpBody() {
+        var ch, str, classMarker, terminated, body;
+
+        ch = source[index];
+        assert(ch === '/', 'Regular expression literal must start with a slash');
+        str = source[index++];
+
+        classMarker = false;
+        terminated = false;
+        while (index < length) {
+            ch = source[index++];
+            str += ch;
+            if (ch === '\\') {
+                ch = source[index++];
+                // ECMA-262 7.8.5
+                if (isLineTerminator(ch.charCodeAt(0))) {
+                    throwUnexpectedToken(null, Messages.UnterminatedRegExp);
+                }
+                str += ch;
+            } else if (isLineTerminator(ch.charCodeAt(0))) {
+                throwUnexpectedToken(null, Messages.UnterminatedRegExp);
+            } else if (classMarker) {
+                if (ch === ']') {
+                    classMarker = false;
+                }
+            } else {
+                if (ch === '/') {
+                    terminated = true;
+                    break;
+                } else if (ch === '[') {
+                    classMarker = true;
+                }
+            }
+        }
+
+        if (!terminated) {
+            throwUnexpectedToken(null, Messages.UnterminatedRegExp);
+        }
+
+        // Exclude leading and trailing slash.
+        body = str.substr(1, str.length - 2);
+        return {
+            value: body,
+            literal: str
+        };
+    }
+
+    function scanRegExpFlags() {
+        var ch, str, flags, restore;
+
+        str = '';
+        flags = '';
+        while (index < length) {
+            ch = source[index];
+            if (!isIdentifierPart(ch.charCodeAt(0))) {
+                break;
+            }
+
+            ++index;
+            if (ch === '\\' && index < length) {
+                ch = source[index];
+                if (ch === 'u') {
+                    ++index;
+                    restore = index;
+                    ch = scanHexEscape('u');
+                    if (ch) {
+                        flags += ch;
+                        for (str += '\\u'; restore < index; ++restore) {
+                            str += source[restore];
+                        }
+                    } else {
+                        index = restore;
+                        flags += 'u';
+                        str += '\\u';
+                    }
+                    tolerateUnexpectedToken();
+                } else {
+                    str += '\\';
+                    tolerateUnexpectedToken();
+                }
+            } else {
+                flags += ch;
+                str += ch;
+            }
+        }
+
+        return {
+            value: flags,
+            literal: str
+        };
+    }
+
+    function scanRegExp() {
+        var start, body, flags, value;
+        scanning = true;
+
+        lookahead = null;
+        skipComment();
+        start = index;
+
+        body = scanRegExpBody();
+        flags = scanRegExpFlags();
+        value = testRegExp(body.value, flags.value);
+        scanning = false;
+        if (extra.tokenize) {
+            return {
+                type: Token.RegularExpression,
+                value: value,
+                regex: {
+                    pattern: body.value,
+                    flags: flags.value
+                },
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                start: start,
+                end: index
+            };
+        }
+
+        return {
+            literal: body.literal + flags.literal,
+            value: value,
+            regex: {
+                pattern: body.value,
+                flags: flags.value
+            },
+            start: start,
+            end: index
+        };
+    }
+
+    function collectRegex() {
+        var pos, loc, regex, token;
+
+        skipComment();
+
+        pos = index;
+        loc = {
+            start: {
+                line: lineNumber,
+                column: index - lineStart
+            }
+        };
+
+        regex = scanRegExp();
+
+        loc.end = {
+            line: lineNumber,
+            column: index - lineStart
+        };
+
+        /* istanbul ignore next */
+        if (!extra.tokenize) {
+            // Pop the previous token, which is likely '/' or '/='
+            if (extra.tokens.length > 0) {
+                token = extra.tokens[extra.tokens.length - 1];
+                if (token.range[0] === pos && token.type === 'Punctuator') {
+                    if (token.value === '/' || token.value === '/=') {
+                        extra.tokens.pop();
+                    }
+                }
+            }
+
+            extra.tokens.push({
+                type: 'RegularExpression',
+                value: regex.literal,
+                regex: regex.regex,
+                range: [pos, index],
+                loc: loc
+            });
+        }
+
+        return regex;
+    }
+
+    function isIdentifierName(token) {
+        return token.type === Token.Identifier ||
+            token.type === Token.Keyword ||
+            token.type === Token.BooleanLiteral ||
+            token.type === Token.NullLiteral;
+    }
+
+    // Using the following algorithm:
+    // https://github.com/mozilla/sweet.js/wiki/design
+
+    function advanceSlash() {
+        var regex, previous, check;
+
+        function testKeyword(value) {
+            return value && (value.length > 1) && (value[0] >= 'a') && (value[0] <= 'z');
+        }
+
+        previous = extra.tokenValues[extra.tokens.length - 1];
+        regex = (previous !== null);
+
+        switch (previous) {
+        case 'this':
+        case ']':
+            regex = false;
+            break;
+
+        case ')':
+            check = extra.tokenValues[extra.openParenToken - 1];
+            regex = (check === 'if' || check === 'while' || check === 'for' || check === 'with');
+            break;
+
+        case '}':
+            // Dividing a function by anything makes little sense,
+            // but we have to check for that.
+            regex = false;
+            if (testKeyword(extra.tokenValues[extra.openCurlyToken - 3])) {
+                // Anonymous function, e.g. function(){} /42
+                check = extra.tokenValues[extra.openCurlyToken - 4];
+                regex = check ? (FnExprTokens.indexOf(check) < 0) : false;
+            } else if (testKeyword(extra.tokenValues[extra.openCurlyToken - 4])) {
+                // Named function, e.g. function f(){} /42/
+                check = extra.tokenValues[extra.openCurlyToken - 5];
+                regex = check ? (FnExprTokens.indexOf(check) < 0) : true;
+            }
+        }
+
+        return regex ? collectRegex() : scanPunctuator();
+    }
+
+    function advance() {
+        var cp, token;
+
+        if (index >= length) {
+            return {
+                type: Token.EOF,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                start: index,
+                end: index
+            };
+        }
+
+        cp = source.charCodeAt(index);
+
+        if (isIdentifierStart(cp)) {
+            token = scanIdentifier();
+            if (strict && isStrictModeReservedWord(token.value)) {
+                token.type = Token.Keyword;
+            }
+            return token;
+        }
+
+        // Very common: ( and ) and ;
+        if (cp === 0x28 || cp === 0x29 || cp === 0x3B) {
+            return scanPunctuator();
+        }
+
+        // String literal starts with single quote (U+0027) or double quote (U+0022).
+        if (cp === 0x27 || cp === 0x22) {
+            return scanStringLiteral();
+        }
+
+        // Dot (.) U+002E can also start a floating-point number, hence the need
+        // to check the next character.
+        if (cp === 0x2E) {
+            if (isDecimalDigit(source.charCodeAt(index + 1))) {
+                return scanNumericLiteral();
+            }
+            return scanPunctuator();
+        }
+
+        if (isDecimalDigit(cp)) {
+            return scanNumericLiteral();
+        }
+
+        // Slash (/) U+002F can also start a regex.
+        if (extra.tokenize && cp === 0x2F) {
+            return advanceSlash();
+        }
+
+        // Template literals start with ` (U+0060) for template head
+        // or } (U+007D) for template middle or template tail.
+        if (cp === 0x60 || (cp === 0x7D && state.curlyStack[state.curlyStack.length - 1] === '${')) {
+            return scanTemplate();
+        }
+
+        // Possible identifier start in a surrogate pair.
+        if (cp >= 0xD800 && cp < 0xDFFF) {
+            cp = codePointAt(index);
+            if (isIdentifierStart(cp)) {
+                return scanIdentifier();
+            }
+        }
+
+        return scanPunctuator();
+    }
+
+    function collectToken() {
+        var loc, token, value, entry;
+
+        loc = {
+            start: {
+                line: lineNumber,
+                column: index - lineStart
+            }
+        };
+
+        token = advance();
+        loc.end = {
+            line: lineNumber,
+            column: index - lineStart
+        };
+
+        if (token.type !== Token.EOF) {
+            value = source.slice(token.start, token.end);
+            entry = {
+                type: TokenName[token.type],
+                value: value,
+                range: [token.start, token.end],
+                loc: loc
+            };
+            if (token.regex) {
+                entry.regex = {
+                    pattern: token.regex.pattern,
+                    flags: token.regex.flags
+                };
+            }
+            if (extra.tokenValues) {
+                extra.tokenValues.push((entry.type === 'Punctuator' || entry.type === 'Keyword') ? entry.value : null);
+            }
+            if (extra.tokenize) {
+                if (!extra.range) {
+                    delete entry.range;
+                }
+                if (!extra.loc) {
+                    delete entry.loc;
+                }
+                if (extra.delegate) {
+                    entry = extra.delegate(entry);
+                }
+            }
+            extra.tokens.push(entry);
+        }
+
+        return token;
+    }
+
+    function lex() {
+        var token;
+        scanning = true;
+
+        lastIndex = index;
+        lastLineNumber = lineNumber;
+        lastLineStart = lineStart;
+
+        skipComment();
+
+        token = lookahead;
+
+        startIndex = index;
+        startLineNumber = lineNumber;
+        startLineStart = lineStart;
+
+        lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
+        scanning = false;
+        return token;
+    }
+
+    function peek() {
+        scanning = true;
+
+        skipComment();
+
+        lastIndex = index;
+        lastLineNumber = lineNumber;
+        lastLineStart = lineStart;
+
+        startIndex = index;
+        startLineNumber = lineNumber;
+        startLineStart = lineStart;
+
+        lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
+        scanning = false;
+    }
+
+    function Position() {
+        this.line = startLineNumber;
+        this.column = startIndex - startLineStart;
+    }
+
+    function SourceLocation() {
+        this.start = new Position();
+        this.end = null;
+    }
+
+    function WrappingSourceLocation(startToken) {
+        this.start = {
+            line: startToken.lineNumber,
+            column: startToken.start - startToken.lineStart
+        };
+        this.end = null;
+    }
+
+    function Node() {
+        if (extra.range) {
+            this.range = [startIndex, 0];
+        }
+        if (extra.loc) {
+            this.loc = new SourceLocation();
+        }
+    }
+
+    function WrappingNode(startToken) {
+        if (extra.range) {
+            this.range = [startToken.start, 0];
+        }
+        if (extra.loc) {
+            this.loc = new WrappingSourceLocation(startToken);
+        }
+    }
+
+    WrappingNode.prototype = Node.prototype = {
+
+        processComment: function () {
+            var lastChild,
+                innerComments,
+                leadingComments,
+                trailingComments,
+                bottomRight = extra.bottomRightStack,
+                i,
+                comment,
+                last = bottomRight[bottomRight.length - 1];
+
+            if (this.type === Syntax.Program) {
+                if (this.body.length > 0) {
+                    return;
+                }
+            }
+            /**
+             * patch innnerComments for properties empty block
+             * `function a() {/** comments **\/}`
+             */
+
+            if (this.type === Syntax.BlockStatement && this.body.length === 0) {
+                innerComments = [];
+                for (i = extra.leadingComments.length - 1; i >= 0; --i) {
+                    comment = extra.leadingComments[i];
+                    if (this.range[1] >= comment.range[1]) {
+                        innerComments.unshift(comment);
+                        extra.leadingComments.splice(i, 1);
+                        extra.trailingComments.splice(i, 1);
+                    }
+                }
+                if (innerComments.length) {
+                    this.innerComments = innerComments;
+                    //bottomRight.push(this);
+                    return;
+                }
+            }
+
+            if (extra.trailingComments.length > 0) {
+                trailingComments = [];
+                for (i = extra.trailingComments.length - 1; i >= 0; --i) {
+                    comment = extra.trailingComments[i];
+                    if (comment.range[0] >= this.range[1]) {
+                        trailingComments.unshift(comment);
+                        extra.trailingComments.splice(i, 1);
+                    }
+                }
+                extra.trailingComments = [];
+            } else {
+                if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) {
+                    trailingComments = last.trailingComments;
+                    delete last.trailingComments;
+                }
+            }
+
+            // Eating the stack.
+            while (last && last.range[0] >= this.range[0]) {
+                lastChild = bottomRight.pop();
+                last = bottomRight[bottomRight.length - 1];
+            }
+
+            if (lastChild) {
+                if (lastChild.leadingComments) {
+                    leadingComments = [];
+                    for (i = lastChild.leadingComments.length - 1; i >= 0; --i) {
+                        comment = lastChild.leadingComments[i];
+                        if (comment.range[1] <= this.range[0]) {
+                            leadingComments.unshift(comment);
+                            lastChild.leadingComments.splice(i, 1);
+                        }
+                    }
+
+                    if (!lastChild.leadingComments.length) {
+                        lastChild.leadingComments = undefined;
+                    }
+                }
+            } else if (extra.leadingComments.length > 0) {
+                leadingComments = [];
+                for (i = extra.leadingComments.length - 1; i >= 0; --i) {
+                    comment = extra.leadingComments[i];
+                    if (comment.range[1] <= this.range[0]) {
+                        leadingComments.unshift(comment);
+                        extra.leadingComments.splice(i, 1);
+                    }
+                }
+            }
+
+
+            if (leadingComments && leadingComments.length > 0) {
+                this.leadingComments = leadingComments;
+            }
+            if (trailingComments && trailingComments.length > 0) {
+                this.trailingComments = trailingComments;
+            }
+
+            bottomRight.push(this);
+        },
+
+        finish: function () {
+            if (extra.range) {
+                this.range[1] = lastIndex;
+            }
+            if (extra.loc) {
+                this.loc.end = {
+                    line: lastLineNumber,
+                    column: lastIndex - lastLineStart
+                };
+                if (extra.source) {
+                    this.loc.source = extra.source;
+                }
+            }
+
+            if (extra.attachComment) {
+                this.processComment();
+            }
+        },
+
+        finishArrayExpression: function (elements) {
+            this.type = Syntax.ArrayExpression;
+            this.elements = elements;
+            this.finish();
+            return this;
+        },
+
+        finishArrayPattern: function (elements) {
+            this.type = Syntax.ArrayPattern;
+            this.elements = elements;
+            this.finish();
+            return this;
+        },
+
+        finishArrowFunctionExpression: function (params, defaults, body, expression) {
+            this.type = Syntax.ArrowFunctionExpression;
+            this.id = null;
+            this.params = params;
+            this.defaults = defaults;
+            this.body = body;
+            this.generator = false;
+            this.expression = expression;
+            this.finish();
+            return this;
+        },
+
+        finishAssignmentExpression: function (operator, left, right) {
+            this.type = Syntax.AssignmentExpression;
+            this.operator = operator;
+            this.left = left;
+            this.right = right;
+            this.finish();
+            return this;
+        },
+
+        finishAssignmentPattern: function (left, right) {
+            this.type = Syntax.AssignmentPattern;
+            this.left = left;
+            this.right = right;
+            this.finish();
+            return this;
+        },
+
+        finishBinaryExpression: function (operator, left, right) {
+            this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression;
+            this.operator = operator;
+            this.left = left;
+            this.right = right;
+            this.finish();
+            return this;
+        },
+
+        finishBlockStatement: function (body) {
+            this.type = Syntax.BlockStatement;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishBreakStatement: function (label) {
+            this.type = Syntax.BreakStatement;
+            this.label = label;
+            this.finish();
+            return this;
+        },
+
+        finishCallExpression: function (callee, args) {
+            this.type = Syntax.CallExpression;
+            this.callee = callee;
+            this.arguments = args;
+            this.finish();
+            return this;
+        },
+
+        finishCatchClause: function (param, body) {
+            this.type = Syntax.CatchClause;
+            this.param = param;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishClassBody: function (body) {
+            this.type = Syntax.ClassBody;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishClassDeclaration: function (id, superClass, body) {
+            this.type = Syntax.ClassDeclaration;
+            this.id = id;
+            this.superClass = superClass;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishClassExpression: function (id, superClass, body) {
+            this.type = Syntax.ClassExpression;
+            this.id = id;
+            this.superClass = superClass;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishConditionalExpression: function (test, consequent, alternate) {
+            this.type = Syntax.ConditionalExpression;
+            this.test = test;
+            this.consequent = consequent;
+            this.alternate = alternate;
+            this.finish();
+            return this;
+        },
+
+        finishContinueStatement: function (label) {
+            this.type = Syntax.ContinueStatement;
+            this.label = label;
+            this.finish();
+            return this;
+        },
+
+        finishDebuggerStatement: function () {
+            this.type = Syntax.DebuggerStatement;
+            this.finish();
+            return this;
+        },
+
+        finishDoWhileStatement: function (body, test) {
+            this.type = Syntax.DoWhileStatement;
+            this.body = body;
+            this.test = test;
+            this.finish();
+            return this;
+        },
+
+        finishEmptyStatement: function () {
+            this.type = Syntax.EmptyStatement;
+            this.finish();
+            return this;
+        },
+
+        finishExpressionStatement: function (expression) {
+            this.type = Syntax.ExpressionStatement;
+            this.expression = expression;
+            this.finish();
+            return this;
+        },
+
+        finishForStatement: function (init, test, update, body) {
+            this.type = Syntax.ForStatement;
+            this.init = init;
+            this.test = test;
+            this.update = update;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishForOfStatement: function (left, right, body) {
+            this.type = Syntax.ForOfStatement;
+            this.left = left;
+            this.right = right;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishForInStatement: function (left, right, body) {
+            this.type = Syntax.ForInStatement;
+            this.left = left;
+            this.right = right;
+            this.body = body;
+            this.each = false;
+            this.finish();
+            return this;
+        },
+
+        finishFunctionDeclaration: function (id, params, defaults, body, generator) {
+            this.type = Syntax.FunctionDeclaration;
+            this.id = id;
+            this.params = params;
+            this.defaults = defaults;
+            this.body = body;
+            this.generator = generator;
+            this.expression = false;
+            this.finish();
+            return this;
+        },
+
+        finishFunctionExpression: function (id, params, defaults, body, generator) {
+            this.type = Syntax.FunctionExpression;
+            this.id = id;
+            this.params = params;
+            this.defaults = defaults;
+            this.body = body;
+            this.generator = generator;
+            this.expression = false;
+            this.finish();
+            return this;
+        },
+
+        finishIdentifier: function (name) {
+            this.type = Syntax.Identifier;
+            this.name = name;
+            this.finish();
+            return this;
+        },
+
+        finishIfStatement: function (test, consequent, alternate) {
+            this.type = Syntax.IfStatement;
+            this.test = test;
+            this.consequent = consequent;
+            this.alternate = alternate;
+            this.finish();
+            return this;
+        },
+
+        finishLabeledStatement: function (label, body) {
+            this.type = Syntax.LabeledStatement;
+            this.label = label;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishLiteral: function (token) {
+            this.type = Syntax.Literal;
+            this.value = token.value;
+            this.raw = source.slice(token.start, token.end);
+            if (token.regex) {
+                this.regex = token.regex;
+            }
+            this.finish();
+            return this;
+        },
+
+        finishMemberExpression: function (accessor, object, property) {
+            this.type = Syntax.MemberExpression;
+            this.computed = accessor === '[';
+            this.object = object;
+            this.property = property;
+            this.finish();
+            return this;
+        },
+
+        finishMetaProperty: function (meta, property) {
+            this.type = Syntax.MetaProperty;
+            this.meta = meta;
+            this.property = property;
+            this.finish();
+            return this;
+        },
+
+        finishNewExpression: function (callee, args) {
+            this.type = Syntax.NewExpression;
+            this.callee = callee;
+            this.arguments = args;
+            this.finish();
+            return this;
+        },
+
+        finishObjectExpression: function (properties) {
+            this.type = Syntax.ObjectExpression;
+            this.properties = properties;
+            this.finish();
+            return this;
+        },
+
+        finishObjectPattern: function (properties) {
+            this.type = Syntax.ObjectPattern;
+            this.properties = properties;
+            this.finish();
+            return this;
+        },
+
+        finishPostfixExpression: function (operator, argument) {
+            this.type = Syntax.UpdateExpression;
+            this.operator = operator;
+            this.argument = argument;
+            this.prefix = false;
+            this.finish();
+            return this;
+        },
+
+        finishProgram: function (body, sourceType) {
+            this.type = Syntax.Program;
+            this.body = body;
+            this.sourceType = sourceType;
+            this.finish();
+            return this;
+        },
+
+        finishProperty: function (kind, key, computed, value, method, shorthand) {
+            this.type = Syntax.Property;
+            this.key = key;
+            this.computed = computed;
+            this.value = value;
+            this.kind = kind;
+            this.method = method;
+            this.shorthand = shorthand;
+            this.finish();
+            return this;
+        },
+
+        finishRestElement: function (argument) {
+            this.type = Syntax.RestElement;
+            this.argument = argument;
+            this.finish();
+            return this;
+        },
+
+        finishReturnStatement: function (argument) {
+            this.type = Syntax.ReturnStatement;
+            this.argument = argument;
+            this.finish();
+            return this;
+        },
+
+        finishSequenceExpression: function (expressions) {
+            this.type = Syntax.SequenceExpression;
+            this.expressions = expressions;
+            this.finish();
+            return this;
+        },
+
+        finishSpreadElement: function (argument) {
+            this.type = Syntax.SpreadElement;
+            this.argument = argument;
+            this.finish();
+            return this;
+        },
+
+        finishSwitchCase: function (test, consequent) {
+            this.type = Syntax.SwitchCase;
+            this.test = test;
+            this.consequent = consequent;
+            this.finish();
+            return this;
+        },
+
+        finishSuper: function () {
+            this.type = Syntax.Super;
+            this.finish();
+            return this;
+        },
+
+        finishSwitchStatement: function (discriminant, cases) {
+            this.type = Syntax.SwitchStatement;
+            this.discriminant = discriminant;
+            this.cases = cases;
+            this.finish();
+            return this;
+        },
+
+        finishTaggedTemplateExpression: function (tag, quasi) {
+            this.type = Syntax.TaggedTemplateExpression;
+            this.tag = tag;
+            this.quasi = quasi;
+            this.finish();
+            return this;
+        },
+
+        finishTemplateElement: function (value, tail) {
+            this.type = Syntax.TemplateElement;
+            this.value = value;
+            this.tail = tail;
+            this.finish();
+            return this;
+        },
+
+        finishTemplateLiteral: function (quasis, expressions) {
+            this.type = Syntax.TemplateLiteral;
+            this.quasis = quasis;
+            this.expressions = expressions;
+            this.finish();
+            return this;
+        },
+
+        finishThisExpression: function () {
+            this.type = Syntax.ThisExpression;
+            this.finish();
+            return this;
+        },
+
+        finishThrowStatement: function (argument) {
+            this.type = Syntax.ThrowStatement;
+            this.argument = argument;
+            this.finish();
+            return this;
+        },
+
+        finishTryStatement: function (block, handler, finalizer) {
+            this.type = Syntax.TryStatement;
+            this.block = block;
+            this.guardedHandlers = [];
+            this.handlers = handler ? [handler] : [];
+            this.handler = handler;
+            this.finalizer = finalizer;
+            this.finish();
+            return this;
+        },
+
+        finishUnaryExpression: function (operator, argument) {
+            this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression;
+            this.operator = operator;
+            this.argument = argument;
+            this.prefix = true;
+            this.finish();
+            return this;
+        },
+
+        finishVariableDeclaration: function (declarations) {
+            this.type = Syntax.VariableDeclaration;
+            this.declarations = declarations;
+            this.kind = 'var';
+            this.finish();
+            return this;
+        },
+
+        finishLexicalDeclaration: function (declarations, kind) {
+            this.type = Syntax.VariableDeclaration;
+            this.declarations = declarations;
+            this.kind = kind;
+            this.finish();
+            return this;
+        },
+
+        finishVariableDeclarator: function (id, init) {
+            this.type = Syntax.VariableDeclarator;
+            this.id = id;
+            this.init = init;
+            this.finish();
+            return this;
+        },
+
+        finishWhileStatement: function (test, body) {
+            this.type = Syntax.WhileStatement;
+            this.test = test;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishWithStatement: function (object, body) {
+            this.type = Syntax.WithStatement;
+            this.object = object;
+            this.body = body;
+            this.finish();
+            return this;
+        },
+
+        finishExportSpecifier: function (local, exported) {
+            this.type = Syntax.ExportSpecifier;
+            this.exported = exported || local;
+            this.local = local;
+            this.finish();
+            return this;
+        },
+
+        finishImportDefaultSpecifier: function (local) {
+            this.type = Syntax.ImportDefaultSpecifier;
+            this.local = local;
+            this.finish();
+            return this;
+        },
+
+        finishImportNamespaceSpecifier: function (local) {
+            this.type = Syntax.ImportNamespaceSpecifier;
+            this.local = local;
+            this.finish();
+            return this;
+        },
+
+        finishExportNamedDeclaration: function (declaration, specifiers, src) {
+            this.type = Syntax.ExportNamedDeclaration;
+            this.declaration = declaration;
+            this.specifiers = specifiers;
+            this.source = src;
+            this.finish();
+            return this;
+        },
+
+        finishExportDefaultDeclaration: function (declaration) {
+            this.type = Syntax.ExportDefaultDeclaration;
+            this.declaration = declaration;
+            this.finish();
+            return this;
+        },
+
+        finishExportAllDeclaration: function (src) {
+            this.type = Syntax.ExportAllDeclaration;
+            this.source = src;
+            this.finish();
+            return this;
+        },
+
+        finishImportSpecifier: function (local, imported) {
+            this.type = Syntax.ImportSpecifier;
+            this.local = local || imported;
+            this.imported = imported;
+            this.finish();
+            return this;
+        },
+
+        finishImportDeclaration: function (specifiers, src) {
+            this.type = Syntax.ImportDeclaration;
+            this.specifiers = specifiers;
+            this.source = src;
+            this.finish();
+            return this;
+        },
+
+        finishYieldExpression: function (argument, delegate) {
+            this.type = Syntax.YieldExpression;
+            this.argument = argument;
+            this.delegate = delegate;
+            this.finish();
+            return this;
+        }
+    };
+
+
+    function recordError(error) {
+        var e, existing;
+
+        for (e = 0; e < extra.errors.length; e++) {
+            existing = extra.errors[e];
+            // Prevent duplicated error.
+            /* istanbul ignore next */
+            if (existing.index === error.index && existing.message === error.message) {
+                return;
+            }
+        }
+
+        extra.errors.push(error);
+    }
+
+    function constructError(msg, column) {
+        var error = new Error(msg);
+        try {
+            throw error;
+        } catch (base) {
+            /* istanbul ignore else */
+            if (Object.create && Object.defineProperty) {
+                error = Object.create(base);
+                Object.defineProperty(error, 'column', { value: column });
+            }
+        } finally {
+            return error;
+        }
+    }
+
+    function createError(line, pos, description) {
+        var msg, column, error;
+
+        msg = 'Line ' + line + ': ' + description;
+        column = pos - (scanning ? lineStart : lastLineStart) + 1;
+        error = constructError(msg, column);
+        error.lineNumber = line;
+        error.description = description;
+        error.index = pos;
+        return error;
+    }
+
+    // Throw an exception
+
+    function throwError(messageFormat) {
+        var args, msg;
+
+        args = Array.prototype.slice.call(arguments, 1);
+        msg = messageFormat.replace(/%(\d)/g,
+            function (whole, idx) {
+                assert(idx < args.length, 'Message reference must be in range');
+                return args[idx];
+            }
+        );
+
+        throw createError(lastLineNumber, lastIndex, msg);
+    }
+
+    function tolerateError(messageFormat) {
+        var args, msg, error;
+
+        args = Array.prototype.slice.call(arguments, 1);
+        /* istanbul ignore next */
+        msg = messageFormat.replace(/%(\d)/g,
+            function (whole, idx) {
+                assert(idx < args.length, 'Message reference must be in range');
+                return args[idx];
+            }
+        );
+
+        error = createError(lineNumber, lastIndex, msg);
+        if (extra.errors) {
+            recordError(error);
+        } else {
+            throw error;
+        }
+    }
+
+    // Throw an exception because of the token.
+
+    function unexpectedTokenError(token, message) {
+        var value, msg = message || Messages.UnexpectedToken;
+
+        if (token) {
+            if (!message) {
+                msg = (token.type === Token.EOF) ? Messages.UnexpectedEOS :
+                    (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier :
+                    (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber :
+                    (token.type === Token.StringLiteral) ? Messages.UnexpectedString :
+                    (token.type === Token.Template) ? Messages.UnexpectedTemplate :
+                    Messages.UnexpectedToken;
+
+                if (token.type === Token.Keyword) {
+                    if (isFutureReservedWord(token.value)) {
+                        msg = Messages.UnexpectedReserved;
+                    } else if (strict && isStrictModeReservedWord(token.value)) {
+                        msg = Messages.StrictReservedWord;
+                    }
+                }
+            }
+
+            value = (token.type === Token.Template) ? token.value.raw : token.value;
+        } else {
+            value = 'ILLEGAL';
+        }
+
+        msg = msg.replace('%0', value);
+
+        return (token && typeof token.lineNumber === 'number') ?
+            createError(token.lineNumber, token.start, msg) :
+            createError(scanning ? lineNumber : lastLineNumber, scanning ? index : lastIndex, msg);
+    }
+
+    function throwUnexpectedToken(token, message) {
+        throw unexpectedTokenError(token, message);
+    }
+
+    function tolerateUnexpectedToken(token, message) {
+        var error = unexpectedTokenError(token, message);
+        if (extra.errors) {
+            recordError(error);
+        } else {
+            throw error;
+        }
+    }
+
+    // Expect the next token to match the specified punctuator.
+    // If not, an exception will be thrown.
+
+    function expect(value) {
+        var token = lex();
+        if (token.type !== Token.Punctuator || token.value !== value) {
+            throwUnexpectedToken(token);
+        }
+    }
+
+    /**
+     * @name expectCommaSeparator
+     * @description Quietly expect a comma when in tolerant mode, otherwise delegates
+     * to <code>expect(value)</code>
+     * @since 2.0
+     */
+    function expectCommaSeparator() {
+        var token;
+
+        if (extra.errors) {
+            token = lookahead;
+            if (token.type === Token.Punctuator && token.value === ',') {
+                lex();
+            } else if (token.type === Token.Punctuator && token.value === ';') {
+                lex();
+                tolerateUnexpectedToken(token);
+            } else {
+                tolerateUnexpectedToken(token, Messages.UnexpectedToken);
+            }
+        } else {
+            expect(',');
+        }
+    }
+
+    // Expect the next token to match the specified keyword.
+    // If not, an exception will be thrown.
+
+    function expectKeyword(keyword) {
+        var token = lex();
+        if (token.type !== Token.Keyword || token.value !== keyword) {
+            throwUnexpectedToken(token);
+        }
+    }
+
+    // Return true if the next token matches the specified punctuator.
+
+    function match(value) {
+        return lookahead.type === Token.Punctuator && lookahead.value === value;
+    }
+
+    // Return true if the next token matches the specified keyword
+
+    function matchKeyword(keyword) {
+        return lookahead.type === Token.Keyword && lookahead.value === keyword;
+    }
+
+    // Return true if the next token matches the specified contextual keyword
+    // (where an identifier is sometimes a keyword depending on the context)
+
+    function matchContextualKeyword(keyword) {
+        return lookahead.type === Token.Identifier && lookahead.value === keyword;
+    }
+
+    // Return true if the next token is an assignment operator
+
+    function matchAssign() {
+        var op;
+
+        if (lookahead.type !== Token.Punctuator) {
+            return false;
+        }
+        op = lookahead.value;
+        return op === '=' ||
+            op === '*=' ||
+            op === '/=' ||
+            op === '%=' ||
+            op === '+=' ||
+            op === '-=' ||
+            op === '<<=' ||
+            op === '>>=' ||
+            op === '>>>=' ||
+            op === '&=' ||
+            op === '^=' ||
+            op === '|=';
+    }
+
+    function consumeSemicolon() {
+        // Catch the very common case first: immediately a semicolon (U+003B).
+        if (source.charCodeAt(startIndex) === 0x3B || match(';')) {
+            lex();
+            return;
+        }
+
+        if (hasLineTerminator) {
+            return;
+        }
+
+        // FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
+        lastIndex = startIndex;
+        lastLineNumber = startLineNumber;
+        lastLineStart = startLineStart;
+
+        if (lookahead.type !== Token.EOF && !match('}')) {
+            throwUnexpectedToken(lookahead);
+        }
+    }
+
+    // Cover grammar support.
+    //
+    // When an assignment expression position starts with an left parenthesis, the determination of the type
+    // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead)
+    // or the first comma. This situation also defers the determination of all the expressions nested in the pair.
+    //
+    // There are three productions that can be parsed in a parentheses pair that needs to be determined
+    // after the outermost pair is closed. They are:
+    //
+    //   1. AssignmentExpression
+    //   2. BindingElements
+    //   3. AssignmentTargets
+    //
+    // In order to avoid exponential backtracking, we use two flags to denote if the production can be
+    // binding element or assignment target.
+    //
+    // The three productions have the relationship:
+    //
+    //   BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression
+    //
+    // with a single exception that CoverInitializedName when used directly in an Expression, generates
+    // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the
+    // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair.
+    //
+    // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not
+    // effect the current flags. This means the production the parser parses is only used as an expression. Therefore
+    // the CoverInitializedName check is conducted.
+    //
+    // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates
+    // the flags outside of the parser. This means the production the parser parses is used as a part of a potential
+    // pattern. The CoverInitializedName check is deferred.
+    function isolateCoverGrammar(parser) {
+        var oldIsBindingElement = isBindingElement,
+            oldIsAssignmentTarget = isAssignmentTarget,
+            oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
+            result;
+        isBindingElement = true;
+        isAssignmentTarget = true;
+        firstCoverInitializedNameError = null;
+        result = parser();
+        if (firstCoverInitializedNameError !== null) {
+            throwUnexpectedToken(firstCoverInitializedNameError);
+        }
+        isBindingElement = oldIsBindingElement;
+        isAssignmentTarget = oldIsAssignmentTarget;
+        firstCoverInitializedNameError = oldFirstCoverInitializedNameError;
+        return result;
+    }
+
+    function inheritCoverGrammar(parser) {
+        var oldIsBindingElement = isBindingElement,
+            oldIsAssignmentTarget = isAssignmentTarget,
+            oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
+            result;
+        isBindingElement = true;
+        isAssignmentTarget = true;
+        firstCoverInitializedNameError = null;
+        result = parser();
+        isBindingElement = isBindingElement && oldIsBindingElement;
+        isAssignmentTarget = isAssignmentTarget && oldIsAssignmentTarget;
+        firstCoverInitializedNameError = oldFirstCoverInitializedNameError || firstCoverInitializedNameError;
+        return result;
+    }
+
+    // ECMA-262 13.3.3 Destructuring Binding Patterns
+
+    function parseArrayPattern(params, kind) {
+        var node = new Node(), elements = [], rest, restNode;
+        expect('[');
+
+        while (!match(']')) {
+            if (match(',')) {
+                lex();
+                elements.push(null);
+            } else {
+                if (match('...')) {
+                    restNode = new Node();
+                    lex();
+                    params.push(lookahead);
+                    rest = parseVariableIdentifier(kind);
+                    elements.push(restNode.finishRestElement(rest));
+                    break;
+                } else {
+                    elements.push(parsePatternWithDefault(params, kind));
+                }
+                if (!match(']')) {
+                    expect(',');
+                }
+            }
+
+        }
+
+        expect(']');
+
+        return node.finishArrayPattern(elements);
+    }
+
+    function parsePropertyPattern(params, kind) {
+        var node = new Node(), key, keyToken, computed = match('['), init;
+        if (lookahead.type === Token.Identifier) {
+            keyToken = lookahead;
+            key = parseVariableIdentifier();
+            if (match('=')) {
+                params.push(keyToken);
+                lex();
+                init = parseAssignmentExpression();
+
+                return node.finishProperty(
+                    'init', key, false,
+                    new WrappingNode(keyToken).finishAssignmentPattern(key, init), false, true);
+            } else if (!match(':')) {
+                params.push(keyToken);
+                return node.finishProperty('init', key, false, key, false, true);
+            }
+        } else {
+            key = parseObjectPropertyKey();
+        }
+        expect(':');
+        init = parsePatternWithDefault(params, kind);
+        return node.finishProperty('init', key, computed, init, false, false);
+    }
+
+    function parseObjectPattern(params, kind) {
+        var node = new Node(), properties = [];
+
+        expect('{');
+
+        while (!match('}')) {
+            properties.push(parsePropertyPattern(params, kind));
+            if (!match('}')) {
+                expect(',');
+            }
+        }
+
+        lex();
+
+        return node.finishObjectPattern(properties);
+    }
+
+    function parsePattern(params, kind) {
+        if (match('[')) {
+            return parseArrayPattern(params, kind);
+        } else if (match('{')) {
+            return parseObjectPattern(params, kind);
+        } else if (matchKeyword('let')) {
+            if (kind === 'const' || kind === 'let') {
+                tolerateUnexpectedToken(lookahead, Messages.UnexpectedToken);
+            }
+        }
+
+        params.push(lookahead);
+        return parseVariableIdentifier(kind);
+    }
+
+    function parsePatternWithDefault(params, kind) {
+        var startToken = lookahead, pattern, previousAllowYield, right;
+        pattern = parsePattern(params, kind);
+        if (match('=')) {
+            lex();
+            previousAllowYield = state.allowYield;
+            state.allowYield = true;
+            right = isolateCoverGrammar(parseAssignmentExpression);
+            state.allowYield = previousAllowYield;
+            pattern = new WrappingNode(startToken).finishAssignmentPattern(pattern, right);
+        }
+        return pattern;
+    }
+
+    // ECMA-262 12.2.5 Array Initializer
+
+    function parseArrayInitializer() {
+        var elements = [], node = new Node(), restSpread;
+
+        expect('[');
+
+        while (!match(']')) {
+            if (match(',')) {
+                lex();
+                elements.push(null);
+            } else if (match('...')) {
+                restSpread = new Node();
+                lex();
+                restSpread.finishSpreadElement(inheritCoverGrammar(parseAssignmentExpression));
+
+                if (!match(']')) {
+                    isAssignmentTarget = isBindingElement = false;
+                    expect(',');
+                }
+                elements.push(restSpread);
+            } else {
+                elements.push(inheritCoverGrammar(parseAssignmentExpression));
+
+                if (!match(']')) {
+                    expect(',');
+                }
+            }
+        }
+
+        lex();
+
+        return node.finishArrayExpression(elements);
+    }
+
+    // ECMA-262 12.2.6 Object Initializer
+
+    function parsePropertyFunction(node, paramInfo, isGenerator) {
+        var previousStrict, body;
+
+        isAssignmentTarget = isBindingElement = false;
+
+        previousStrict = strict;
+        body = isolateCoverGrammar(parseFunctionSourceElements);
+
+        if (strict && paramInfo.firstRestricted) {
+            tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message);
+        }
+        if (strict && paramInfo.stricted) {
+            tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message);
+        }
+
+        strict = previousStrict;
+        return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body, isGenerator);
+    }
+
+    function parsePropertyMethodFunction() {
+        var params, method, node = new Node(),
+            previousAllowYield = state.allowYield;
+
+        state.allowYield = false;
+        params = parseParams();
+        state.allowYield = previousAllowYield;
+
+        state.allowYield = false;
+        method = parsePropertyFunction(node, params, false);
+        state.allowYield = previousAllowYield;
+
+        return method;
+    }
+
+    function parseObjectPropertyKey() {
+        var token, node = new Node(), expr;
+
+        token = lex();
+
+        // Note: This function is called only from parseObjectProperty(), where
+        // EOF and Punctuator tokens are already filtered out.
+
+        switch (token.type) {
+        case Token.StringLiteral:
+        case Token.NumericLiteral:
+            if (strict && token.octal) {
+                tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
+            }
+            return node.finishLiteral(token);
+        case Token.Identifier:
+        case Token.BooleanLiteral:
+        case Token.NullLiteral:
+        case Token.Keyword:
+            return node.finishIdentifier(token.value);
+        case Token.Punctuator:
+            if (token.value === '[') {
+                expr = isolateCoverGrammar(parseAssignmentExpression);
+                expect(']');
+                return expr;
+            }
+            break;
+        }
+        throwUnexpectedToken(token);
+    }
+
+    function lookaheadPropertyName() {
+        switch (lookahead.type) {
+        case Token.Identifier:
+        case Token.StringLiteral:
+        case Token.BooleanLiteral:
+        case Token.NullLiteral:
+        case Token.NumericLiteral:
+        case Token.Keyword:
+            return true;
+        case Token.Punctuator:
+            return lookahead.value === '[';
+        }
+        return false;
+    }
+
+    // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
+    // it might be called at a position where there is in fact a short hand identifier pattern or a data property.
+    // This can only be determined after we consumed up to the left parentheses.
+    //
+    // In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
+    // is responsible to visit other options.
+    function tryParseMethodDefinition(token, key, computed, node) {
+        var value, options, methodNode, params,
+            previousAllowYield = state.allowYield;
+
+        if (token.type === Token.Identifier) {
+            // check for `get` and `set`;
+
+            if (token.value === 'get' && lookaheadPropertyName()) {
+                computed = match('[');
+                key = parseObjectPropertyKey();
+                methodNode = new Node();
+                expect('(');
+                expect(')');
+
+                state.allowYield = false;
+                value = parsePropertyFunction(methodNode, {
+                    params: [],
+                    defaults: [],
+                    stricted: null,
+                    firstRestricted: null,
+                    message: null
+                }, false);
+                state.allowYield = previousAllowYield;
+
+                return node.finishProperty('get', key, computed, value, false, false);
+            } else if (token.value === 'set' && lookaheadPropertyName()) {
+                computed = match('[');
+                key = parseObjectPropertyKey();
+                methodNode = new Node();
+                expect('(');
+
+                options = {
+                    params: [],
+                    defaultCount: 0,
+                    defaults: [],
+                    firstRestricted: null,
+                    paramSet: {}
+                };
+                if (match(')')) {
+                    tolerateUnexpectedToken(lookahead);
+                } else {
+                    state.allowYield = false;
+                    parseParam(options);
+                    state.allowYield = previousAllowYield;
+                    if (options.defaultCount === 0) {
+                        options.defaults = [];
+                    }
+                }
+                expect(')');
+
+                state.allowYield = false;
+                value = parsePropertyFunction(methodNode, options, false);
+                state.allowYield = previousAllowYield;
+
+                return node.finishProperty('set', key, computed, value, false, false);
+            }
+        } else if (token.type === Token.Punctuator && token.value === '*' && lookaheadPropertyName()) {
+            computed = match('[');
+            key = parseObjectPropertyKey();
+            methodNode = new Node();
+
+            state.allowYield = true;
+            params = parseParams();
+            state.allowYield = previousAllowYield;
+
+            state.allowYield = false;
+            value = parsePropertyFunction(methodNode, params, true);
+            state.allowYield = previousAllowYield;
+
+            return node.finishProperty('init', key, computed, value, true, false);
+        }
+
+        if (key && match('(')) {
+            value = parsePropertyMethodFunction();
+            return node.finishProperty('init', key, computed, value, true, false);
+        }
+
+        // Not a MethodDefinition.
+        return null;
+    }
+
+    function parseObjectProperty(hasProto) {
+        var token = lookahead, node = new Node(), computed, key, maybeMethod, proto, value;
+
+        computed = match('[');
+        if (match('*')) {
+            lex();
+        } else {
+            key = parseObjectPropertyKey();
+        }
+        maybeMethod = tryParseMethodDefinition(token, key, computed, node);
+        if (maybeMethod) {
+            return maybeMethod;
+        }
+
+        if (!key) {
+            throwUnexpectedToken(lookahead);
+        }
+
+        // Check for duplicated __proto__
+        if (!computed) {
+            proto = (key.type === Syntax.Identifier && key.name === '__proto__') ||
+                (key.type === Syntax.Literal && key.value === '__proto__');
+            if (hasProto.value && proto) {
+                tolerateError(Messages.DuplicateProtoProperty);
+            }
+            hasProto.value |= proto;
+        }
+
+        if (match(':')) {
+            lex();
+            value = inheritCoverGrammar(parseAssignmentExpression);
+            return node.finishProperty('init', key, computed, value, false, false);
+        }
+
+        if (token.type === Token.Identifier) {
+            if (match('=')) {
+                firstCoverInitializedNameError = lookahead;
+                lex();
+                value = isolateCoverGrammar(parseAssignmentExpression);
+                return node.finishProperty('init', key, computed,
+                    new WrappingNode(token).finishAssignmentPattern(key, value), false, true);
+            }
+            return node.finishProperty('init', key, computed, key, false, true);
+        }
+
+        throwUnexpectedToken(lookahead);
+    }
+
+    function parseObjectInitializer() {
+        var properties = [], hasProto = {value: false}, node = new Node();
+
+        expect('{');
+
+        while (!match('}')) {
+            properties.push(parseObjectProperty(hasProto));
+
+            if (!match('}')) {
+                expectCommaSeparator();
+            }
+        }
+
+        expect('}');
+
+        return node.finishObjectExpression(properties);
+    }
+
+    function reinterpretExpressionAsPattern(expr) {
+        var i;
+        switch (expr.type) {
+        case Syntax.Identifier:
+        case Syntax.MemberExpression:
+        case Syntax.RestElement:
+        case Syntax.AssignmentPattern:
+            break;
+        case Syntax.SpreadElement:
+            expr.type = Syntax.RestElement;
+            reinterpretExpressionAsPattern(expr.argument);
+            break;
+        case Syntax.ArrayExpression:
+            expr.type = Syntax.ArrayPattern;
+            for (i = 0; i < expr.elements.length; i++) {
+                if (expr.elements[i] !== null) {
+                    reinterpretExpressionAsPattern(expr.elements[i]);
+                }
+            }
+            break;
+        case Syntax.ObjectExpression:
+            expr.type = Syntax.ObjectPattern;
+            for (i = 0; i < expr.properties.length; i++) {
+                reinterpretExpressionAsPattern(expr.properties[i].value);
+            }
+            break;
+        case Syntax.AssignmentExpression:
+            expr.type = Syntax.AssignmentPattern;
+            reinterpretExpressionAsPattern(expr.left);
+            break;
+        default:
+            // Allow other node type for tolerant parsing.
+            break;
+        }
+    }
+
+    // ECMA-262 12.2.9 Template Literals
+
+    function parseTemplateElement(option) {
+        var node, token;
+
+        if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) {
+            throwUnexpectedToken();
+        }
+
+        node = new Node();
+        token = lex();
+
+        return node.finishTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail);
+    }
+
+    function parseTemplateLiteral() {
+        var quasi, quasis, expressions, node = new Node();
+
+        quasi = parseTemplateElement({ head: true });
+        quasis = [quasi];
+        expressions = [];
+
+        while (!quasi.tail) {
+            expressions.push(parseExpression());
+            quasi = parseTemplateElement({ head: false });
+            quasis.push(quasi);
+        }
+
+        return node.finishTemplateLiteral(quasis, expressions);
+    }
+
+    // ECMA-262 12.2.10 The Grouping Operator
+
+    function parseGroupExpression() {
+        var expr, expressions, startToken, i, params = [];
+
+        expect('(');
+
+        if (match(')')) {
+            lex();
+            if (!match('=>')) {
+                expect('=>');
+            }
+            return {
+                type: PlaceHolders.ArrowParameterPlaceHolder,
+                params: [],
+                rawParams: []
+            };
+        }
+
+        startToken = lookahead;
+        if (match('...')) {
+            expr = parseRestElement(params);
+            expect(')');
+            if (!match('=>')) {
+                expect('=>');
+            }
+            return {
+                type: PlaceHolders.ArrowParameterPlaceHolder,
+                params: [expr]
+            };
+        }
+
+        isBindingElement = true;
+        expr = inheritCoverGrammar(parseAssignmentExpression);
+
+        if (match(',')) {
+            isAssignmentTarget = false;
+            expressions = [expr];
+
+            while (startIndex < length) {
+                if (!match(',')) {
+                    break;
+                }
+                lex();
+
+                if (match('...')) {
+                    if (!isBindingElement) {
+                        throwUnexpectedToken(lookahead);
+                    }
+                    expressions.push(parseRestElement(params));
+                    expect(')');
+                    if (!match('=>')) {
+                        expect('=>');
+                    }
+                    isBindingElement = false;
+                    for (i = 0; i < expressions.length; i++) {
+                        reinterpretExpressionAsPattern(expressions[i]);
+                    }
+                    return {
+                        type: PlaceHolders.ArrowParameterPlaceHolder,
+                        params: expressions
+                    };
+                }
+
+                expressions.push(inheritCoverGrammar(parseAssignmentExpression));
+            }
+
+            expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
+        }
+
+
+        expect(')');
+
+        if (match('=>')) {
+            if (expr.type === Syntax.Identifier && expr.name === 'yield') {
+                return {
+                    type: PlaceHolders.ArrowParameterPlaceHolder,
+                    params: [expr]
+                };
+            }
+
+            if (!isBindingElement) {
+                throwUnexpectedToken(lookahead);
+            }
+
+            if (expr.type === Syntax.SequenceExpression) {
+                for (i = 0; i < expr.expressions.length; i++) {
+                    reinterpretExpressionAsPattern(expr.expressions[i]);
+                }
+            } else {
+                reinterpretExpressionAsPattern(expr);
+            }
+
+            expr = {
+                type: PlaceHolders.ArrowParameterPlaceHolder,
+                params: expr.type === Syntax.SequenceExpression ? expr.expressions : [expr]
+            };
+        }
+        isBindingElement = false;
+        return expr;
+    }
+
+
+    // ECMA-262 12.2 Primary Expressions
+
+    function parsePrimaryExpression() {
+        var type, token, expr, node;
+
+        if (match('(')) {
+            isBindingElement = false;
+            return inheritCoverGrammar(parseGroupExpression);
+        }
+
+        if (match('[')) {
+            return inheritCoverGrammar(parseArrayInitializer);
+        }
+
+        if (match('{')) {
+            return inheritCoverGrammar(parseObjectInitializer);
+        }
+
+        type = lookahead.type;
+        node = new Node();
+
+        if (type === Token.Identifier) {
+            if (state.sourceType === 'module' && lookahead.value === 'await') {
+                tolerateUnexpectedToken(lookahead);
+            }
+            expr = node.finishIdentifier(lex().value);
+        } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+            isAssignmentTarget = isBindingElement = false;
+            if (strict && lookahead.octal) {
+                tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral);
+            }
+            expr = node.finishLiteral(lex());
+        } else if (type === Token.Keyword) {
+            if (!strict && state.allowYield && matchKeyword('yield')) {
+                return parseNonComputedProperty();
+            }
+            if (!strict && matchKeyword('let')) {
+                return node.finishIdentifier(lex().value);
+            }
+            isAssignmentTarget = isBindingElement = false;
+            if (matchKeyword('function')) {
+                return parseFunctionExpression();
+            }
+            if (matchKeyword('this')) {
+                lex();
+                return node.finishThisExpression();
+            }
+            if (matchKeyword('class')) {
+                return parseClassExpression();
+            }
+            throwUnexpectedToken(lex());
+        } else if (type === Token.BooleanLiteral) {
+            isAssignmentTarget = isBindingElement = false;
+            token = lex();
+            token.value = (token.value === 'true');
+            expr = node.finishLiteral(token);
+        } else if (type === Token.NullLiteral) {
+            isAssignmentTarget = isBindingElement = false;
+            token = lex();
+            token.value = null;
+            expr = node.finishLiteral(token);
+        } else if (match('/') || match('/=')) {
+            isAssignmentTarget = isBindingElement = false;
+            index = startIndex;
+
+            if (typeof extra.tokens !== 'undefined') {
+                token = collectRegex();
+            } else {
+                token = scanRegExp();
+            }
+            lex();
+            expr = node.finishLiteral(token);
+        } else if (type === Token.Template) {
... 184060 lines suppressed ...


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org