diff -pruN 0.1.7-5/atKeynames.js 0.2.2-0ubuntu3/atKeynames.js
--- 0.1.7-5/atKeynames.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/atKeynames.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,183 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-/*
- * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Thomas Roell not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission.  Thomas Roell makes no representations
- * about the suitability of this software for any purpose.  It is provided
- * "as is" without express or implied warranty.
- *
- * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- *
- */
-/*
- * Copyright (c) 1994-2003 by The XFree86 Project, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Except as contained in this notice, the name of the copyright holder(s)
- * and author(s) shall not be used in advertising or otherwise to promote
- * the sale, use or other dealings in this Software without prior written
- * authorization from the copyright holder(s) and author(s).
- */
-
-/*
- * NOTE: The AT/MF keyboards can generate (via the 8042) two (MF: three)
- *       sets of scancodes. Set3 can only be generated by a MF keyboard.
- *       Set2 sends a makecode for keypress, and the same code prefixed by a
- *       F0 for keyrelease. This is a little bit ugly to handle. Thus we use
- *       here for X386 the PC/XT compatible Set1. This set uses 8bit scancodes.
- *       Bit 7 ist set if the key is released. The code E0 switches to a
- *       different meaning to add the new MF cursorkeys, while not breaking old
- *       applications. E1 is another special prefix. Since I assume that there
- *       will be further versions of PC/XT scancode compatible keyboards, we
- *       may be in trouble one day.
- *
- * IDEA: 1) Use Set2 on AT84 keyboards and translate it to MF Set3.
- *       2) Use the keyboards native set and translate it to common keysyms.
- */
-
-/*
- * definition of the AT84/MF101/MF102 Keyboard:
- * ============================================================
- *       Defined             Key Cap Glyphs       Pressed value
- *      Key Name            Main       Also       (hex)    (dec)
- *      ----------------   ---------- -------    ------    ------
- */
-
-var KEY_Escape      =/* Escape                0x01  */    1
-var KEY_1           =/* 1           !         0x02  */    2
-var KEY_2           =/* 2           @         0x03  */    3
-var KEY_3           =/* 3           #         0x04  */    4
-var KEY_4           =/* 4           $         0x05  */    5
-var KEY_5           =/* 5           %         0x06  */    6
-var KEY_6           =/* 6           ^         0x07  */    7
-var KEY_7           =/* 7           &         0x08  */    8
-var KEY_8           =/* 8           *         0x09  */    9
-var KEY_9           =/* 9           (         0x0a  */   10
-var KEY_0           =/* 0           )         0x0b  */   11
-var KEY_Minus       =/* - (Minus)   _ (Under) 0x0c  */   12
-var KEY_Equal       =/* = (Equal)   +         0x0d  */   13
-var KEY_BackSpace   =/* Back Space            0x0e  */   14
-var KEY_Tab         =/* Tab                   0x0f  */   15
-var KEY_Q           =/* Q                     0x10  */   16
-var KEY_W           =/* W                     0x11  */   17
-var KEY_E           =/* E                     0x12  */   18
-var KEY_R           =/* R                     0x13  */   19
-var KEY_T           =/* T                     0x14  */   20
-var KEY_Y           =/* Y                     0x15  */   21
-var KEY_U           =/* U                     0x16  */   22
-var KEY_I           =/* I                     0x17  */   23
-var KEY_O           =/* O                     0x18  */   24
-var KEY_P           =/* P                     0x19  */   25
-var KEY_LBrace      =/* [           {         0x1a  */   26
-var KEY_RBrace      =/* ]           }         0x1b  */   27
-var KEY_Enter       =/* Enter                 0x1c  */   28
-var KEY_LCtrl       =/* Ctrl(left)            0x1d  */   29
-var KEY_A           =/* A                     0x1e  */   30
-var KEY_S           =/* S                     0x1f  */   31
-var KEY_D           =/* D                     0x20  */   32
-var KEY_F           =/* F                     0x21  */   33
-var KEY_G           =/* G                     0x22  */   34
-var KEY_H           =/* H                     0x23  */   35
-var KEY_J           =/* J                     0x24  */   36
-var KEY_K           =/* K                     0x25  */   37
-var KEY_L           =/* L                     0x26  */   38
-var KEY_SemiColon   =/* ;(SemiColon) :(Colon) 0x27  */   39
-var KEY_Quote       =/* ' (Apostr)  " (Quote) 0x28  */   40
-var KEY_Tilde       =/* ` (Accent)  ~ (Tilde) 0x29  */   41
-var KEY_ShiftL      =/* Shift(left)           0x2a  */   42
-var KEY_BSlash      =/* \(BckSlash) |(VertBar)0x2b  */   43
-var KEY_Z           =/* Z                     0x2c  */   44
-var KEY_X           =/* X                     0x2d  */   45
-var KEY_C           =/* C                     0x2e  */   46
-var KEY_V           =/* V                     0x2f  */   47
-var KEY_B           =/* B                     0x30  */   48
-var KEY_N           =/* N                     0x31  */   49
-var KEY_M           =/* M                     0x32  */   50
-var KEY_Comma       =/* , (Comma)   < (Less)  0x33  */   51
-var KEY_Period      =/* . (Period)  >(Greater)0x34  */   52
-var KEY_Slash       =/* / (Slash)   ?         0x35  */   53
-var KEY_ShiftR      =/* Shift(right)          0x36  */   54
-var KEY_KP_Multiply =/* *                     0x37  */   55
-var KEY_Alt         =/* Alt(left)             0x38  */   56
-var KEY_Space       =/*   (SpaceBar)          0x39  */   57
-var KEY_CapsLock    =/* CapsLock              0x3a  */   58
-var KEY_F1          =/* F1                    0x3b  */   59
-var KEY_F2          =/* F2                    0x3c  */   60
-var KEY_F3          =/* F3                    0x3d  */   61
-var KEY_F4          =/* F4                    0x3e  */   62
-var KEY_F5          =/* F5                    0x3f  */   63
-var KEY_F6          =/* F6                    0x40  */   64
-var KEY_F7          =/* F7                    0x41  */   65
-var KEY_F8          =/* F8                    0x42  */   66
-var KEY_F9          =/* F9                    0x43  */   67
-var KEY_F10         =/* F10                   0x44  */   68
-var KEY_NumLock     =/* NumLock               0x45  */   69
-var KEY_ScrollLock  =/* ScrollLock            0x46  */   70
-var KEY_KP_7        =/* 7           Home      0x47  */   71
-var KEY_KP_8        =/* 8           Up        0x48  */   72
-var KEY_KP_9        =/* 9           PgUp      0x49  */   73
-var KEY_KP_Minus    =/* - (Minus)             0x4a  */   74
-var KEY_KP_4        =/* 4           Left      0x4b  */   75
-var KEY_KP_5        =/* 5                     0x4c  */   76
-var KEY_KP_6        =/* 6           Right     0x4d  */   77
-var KEY_KP_Plus     =/* + (Plus)              0x4e  */   78
-var KEY_KP_1        =/* 1           End       0x4f  */   79
-var KEY_KP_2        =/* 2           Down      0x50  */   80
-var KEY_KP_3        =/* 3           PgDown    0x51  */   81
-var KEY_KP_0        =/* 0           Insert    0x52  */   82
-var KEY_KP_Decimal  =/* . (Decimal) Delete    0x53  */   83
-var KEY_SysReqest   =/* SysReqest             0x54  */   84
-                         /* NOTUSED               0x55  */
-var KEY_Less        =/* < (Less)   >(Greater) 0x56  */   86
-var KEY_F11         =/* F11                   0x57  */   87
-var KEY_F12         =/* F12                   0x58  */   88
-
-var KEY_Prefix0     =/* special               0x60  */   96
-var KEY_Prefix1     =/* specail               0x61  */   97
diff -pruN 0.1.7-5/bitmap.js 0.2.2-0ubuntu3/bitmap.js
--- 0.1.7-5/bitmap.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/bitmap.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,51 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-
-/*----------------------------------------------------------------------------
-**  bitmap.js
-**      Handle SPICE_IMAGE_TYPE_BITMAP
-**--------------------------------------------------------------------------*/
-function convert_spice_bitmap_to_web(context, spice_bitmap)
-{
-    var ret;
-    var offset, x;
-    var u8 = new Uint8Array(spice_bitmap.data);
-    if (spice_bitmap.format != SPICE_BITMAP_FMT_32BIT &&
-        spice_bitmap.format != SPICE_BITMAP_FMT_RGBA)
-        return undefined;
-
-    ret = context.createImageData(spice_bitmap.x, spice_bitmap.y);
-    for (offset = 0; offset < (spice_bitmap.y * spice_bitmap.stride); )
-        for (x = 0; x < spice_bitmap.x; x++, offset += 4)
-        {
-            ret.data[offset + 0 ] = u8[offset + 2];
-            ret.data[offset + 1 ] = u8[offset + 1];
-            ret.data[offset + 2 ] = u8[offset + 0];
-
-            // FIXME - We effectively treat all images as having SPICE_IMAGE_FLAGS_HIGH_BITS_SET
-            if (spice_bitmap.format == SPICE_BITMAP_FMT_32BIT)
-                ret.data[offset + 3] = 255;
-            else
-                ret.data[offset + 3] = u8[offset];
-        }
-
-    return ret;
-}
diff -pruN 0.1.7-5/cursor.js 0.2.2-0ubuntu3/cursor.js
--- 0.1.7-5/cursor.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/cursor.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,128 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-
-/*----------------------------------------------------------------------------
-**  SpiceCursorConn
-**      Drive the Spice Cursor Channel
-**--------------------------------------------------------------------------*/
-function SpiceCursorConn()
-{
-    SpiceConn.apply(this, arguments);
-}
-
-SpiceCursorConn.prototype = Object.create(SpiceConn.prototype);
-SpiceCursorConn.prototype.process_channel_message = function(msg)
-{
-    if (msg.type == SPICE_MSG_CURSOR_INIT)
-    {
-        var cursor_init = new SpiceMsgCursorInit(msg.data);
-        DEBUG > 1 && console.log("SpiceMsgCursorInit");
-        if (this.parent && this.parent.inputs &&
-            this.parent.inputs.mouse_mode == SPICE_MOUSE_MODE_SERVER)
-        {
-            // FIXME - this imagines that the server actually
-            //          provides the current cursor position,
-            //          instead of 0,0.  As of May 11, 2012,
-            //          that assumption was false :-(.
-            this.parent.inputs.mousex = cursor_init.position.x;
-            this.parent.inputs.mousey = cursor_init.position.y;
-        }
-        // FIXME - We don't handle most of the parameters here...
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_CURSOR_SET)
-    {
-        var cursor_set = new SpiceMsgCursorSet(msg.data);
-        DEBUG > 1 && console.log("SpiceMsgCursorSet");
-        if (cursor_set.flags & SPICE_CURSOR_FLAGS_NONE)
-        {
-            document.getElementById(this.parent.screen_id).style.cursor = "none";
-            return true;
-        }
-
-        if (cursor_set.flags > 0)
-            this.log_warn("FIXME: No support for cursor flags " + cursor_set.flags);
-
-        if (cursor_set.cursor.header.type != SPICE_CURSOR_TYPE_ALPHA)
-        {
-            this.log_warn("FIXME: No support for cursor type " + cursor_set.cursor.header.type);
-            return false;
-        }
-
-        this.set_cursor(cursor_set.cursor);
-
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_CURSOR_MOVE)
-    {
-        this.known_unimplemented(msg.type, "Cursor Move");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_CURSOR_HIDE)
-    {
-        DEBUG > 1 && console.log("SpiceMsgCursorHide");
-        document.getElementById(this.parent.screen_id).style.cursor = "none";
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_CURSOR_TRAIL)
-    {
-        this.known_unimplemented(msg.type, "Cursor Trail");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_CURSOR_RESET)
-    {
-        DEBUG > 1 && console.log("SpiceMsgCursorReset");
-        document.getElementById(this.parent.screen_id).style.cursor = "auto";
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_CURSOR_INVAL_ONE)
-    {
-        this.known_unimplemented(msg.type, "Cursor Inval One");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_CURSOR_INVAL_ALL)
-    {
-        DEBUG > 1 && console.log("SpiceMsgCursorInvalAll");
-        // FIXME - There may be something useful to do here...
-        return true;
-    }
-
-    return false;
-}
-
-SpiceCursorConn.prototype.set_cursor = function(cursor)
-{
-    var pngstr = create_rgba_png(cursor.header.height, cursor.header.width, cursor.data);
-    var curstr = 'url(data:image/png,' + pngstr + ') ' + 
-        cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default";
-    var screen = document.getElementById(this.parent.screen_id);
-    screen.style.cursor = 'auto';
-    screen.style.cursor = curstr;
-    if (window.getComputedStyle(screen, null).cursor == 'auto')
-        SpiceSimulateCursor.simulate_cursor(this, cursor, screen, pngstr);
-}
diff -pruN 0.1.7-5/debian/changelog 0.2.2-0ubuntu3/debian/changelog
--- 0.1.7-5/debian/changelog	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/changelog	2021-05-06 18:07:27.000000000 +0000
@@ -1,9 +1,30 @@
-spice-html5 (0.1.7-5) unstable; urgency=medium
+spice-html5 (0.2.2-0ubuntu3) impish; urgency=medium
 
-  * Removed Liang Guo from the uploaders list (Closes: #961612).
-  * Switched to debhelper-compat = 11.
+  * d/p/lp1926455-01-add-sc-to-send-ctr-alt-del.patch
+  * d/p/lp1926455-02-add-ctrl-alt-del-with-associated-js-eventlistener.patch
+    - Fixing 'Send CTRL-ALT-DEL' button which doesn't work. (LP: #1926455)
 
- -- Thomas Goirand <zigo@debian.org>  Wed, 27 May 2020 17:10:10 +0200
+ -- Eric Desrochers <eric.desrochers@canonical.com>  Thu, 06 May 2021 14:07:27 -0400
+
+spice-html5 (0.2.2-0ubuntu2) focal; urgency=medium
+
+  * d/control: Switch Recommends websockify->python3-websockify to
+    avoid inclusion of websockify in Ubuntu main and to represent
+    the dependency on the websockify binary which is provided by
+    python3-websockify.
+
+ -- James Page <james.page@ubuntu.com>  Mon, 20 Apr 2020 16:37:09 +0100
+
+spice-html5 (0.2.2-0ubuntu1) focal; urgency=medium
+
+  * New upstream release, completing Ubuntu MIR actions (LP: #1108935):
+    - d/p/fix-windows-spice-upside-down.patch: Drop, included in
+      upstream release.
+    - d/p/Handle_non_topdown_bitmaps.patch: Drop, included in
+      upstream release.
+    - d/install: Refactor for src subdirectory for .js files.
+
+ -- James Page <james.page@ubuntu.com>  Wed, 01 Apr 2020 09:56:44 +0100
 
 spice-html5 (0.1.7-4) unstable; urgency=medium
 
diff -pruN 0.1.7-5/debian/control 0.2.2-0ubuntu3/debian/control
--- 0.1.7-5/debian/control	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/control	2020-04-20 15:31:15.000000000 +0000
@@ -1,11 +1,13 @@
 Source: spice-html5
 Section: web
 Priority: optional
-Maintainer: Debian OpenStack <team+openstack@tracker.debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: Debian OpenStack <team+openstack@tracker.debian.org>
 Uploaders:
  Thomas Goirand <zigo@debian.org>,
+ Liang Guo <guoliang@debian.org>,
 Build-Depends:
- debhelper-compat (= 11),
+ debhelper-compat (= 9),
  openstack-pkg-tools,
 Standards-Version: 4.1.3
 Vcs-Browser: https://salsa.debian.org/openstack-team/third-party/spice-html5
@@ -17,7 +19,7 @@ Architecture: all
 Pre-Depends:
  dpkg (>= 1.15.6~),
 Recommends:
- websockify,
+ python3-websockify,
 Depends:
  ${misc:Depends},
 Description: Spice Web client which runs entirely within a modern browser
diff -pruN 0.1.7-5/debian/install 0.2.2-0ubuntu3/debian/install
--- 0.1.7-5/debian/install	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/install	2020-04-01 09:16:44.000000000 +0000
@@ -1,4 +1,3 @@
-*.css	/usr/share/spice-html5
-*.html	/usr/share/spice-html5
-*.js	/usr/share/spice-html5
-thirdparty	/usr/share/spice-html5
+*.css /usr/share/spice-html5
+*.html /usr/share/spice-html5
+src /usr/share/spice-html5
diff -pruN 0.1.7-5/debian/patches/add-ctrl-alt-del-button.patch 0.2.2-0ubuntu3/debian/patches/add-ctrl-alt-del-button.patch
--- 0.1.7-5/debian/patches/add-ctrl-alt-del-button.patch	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/patches/add-ctrl-alt-del-button.patch	2020-04-01 09:16:44.000000000 +0000
@@ -3,9 +3,9 @@ Author: Thomas Goirand <zigo@debian.org>
 Origin: upstream, https://www.spinics.net/lists/spice-devel/msg30943.html
 Last-Update: 2018-02-13
 
---- spice-html5-0.1.7.orig/spice_auto.html
-+++ spice-html5-0.1.7/spice_auto.html
-@@ -191,6 +191,7 @@
+--- a/spice_auto.html
++++ b/spice_auto.html
+@@ -199,6 +199,7 @@
  
          <div id="login">
              <span class="logo">SPICE</span>
diff -pruN 0.1.7-5/debian/patches/fix-windows-spice-upside-down.patch 0.2.2-0ubuntu3/debian/patches/fix-windows-spice-upside-down.patch
--- 0.1.7-5/debian/patches/fix-windows-spice-upside-down.patch	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/patches/fix-windows-spice-upside-down.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,53 +0,0 @@
-Description: Handling non-topdown lz_rgb
-Author: Vincent Desprez <vincent.desprez@apwise.com>
-Origin: upstream, https://gitlab.com/spice/spice-html5/commit/bfa85a7117fcf28ff19f2507f61db4620da2e828
-Last-Update: 2018-08-16
-
-diff --git a/display.js b/display.js
-index 12fbab0..464c72d 100644
---- a/display.js
-+++ b/display.js
-@@ -288,9 +288,6 @@ SpiceDisplayConn.prototype.process_channel_message = function(msg)
-                     return false;
-                 }
- 
--                if (draw_copy.data.src_bitmap.lz_rgb.top_down != 1)
--                    this.log_warn("FIXME: Implement non top down support for lz_rgb");
--
-                 var source_img = convert_spice_lz_to_web(canvas.context,
-                                             draw_copy.data.src_bitmap.lz_rgb);
-                 if (! source_img)
-diff --git a/lz.js b/lz.js
-index 4292eac..53c1141 100644
---- a/lz.js
-+++ b/lz.js
-@@ -141,6 +141,19 @@ function lz_rgb32_decompress(in_buf, at, out_buf, type, default_alpha)
-     return encoder - 1;
- }
- 
-+function flip_image_data(img)
-+{
-+    var wb = img.width * 4;
-+    var h = img.height;
-+    var temp_h = h;
-+    var buff = new Uint8Array(img.width * img.height * 4);
-+    while (temp_h--)
-+    {
-+        buff.set(img.data.subarray(temp_h * wb, (temp_h + 1) * wb), (h - temp_h - 1) * wb);
-+    }
-+    img.data.set(buff);
-+}
-+
- function convert_spice_lz_to_web(context, lz_image)
- {
-     var at;
-@@ -150,6 +163,9 @@ function convert_spice_lz_to_web(context, lz_image)
-         var ret = context.createImageData(lz_image.width, lz_image.height);
- 
-         at = lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGB32, lz_image.type != LZ_IMAGE_TYPE_RGBA);
-+        if (!lz_image.top_down)
-+            flip_image_data(ret);
-+
-         if (lz_image.type == LZ_IMAGE_TYPE_RGBA)
-             lz_rgb32_decompress(u8, at, ret.data, LZ_IMAGE_TYPE_RGBA, false);
-     }
diff -pruN 0.1.7-5/debian/patches/Handle_non_topdown_bitmaps.patch 0.2.2-0ubuntu3/debian/patches/Handle_non_topdown_bitmaps.patch
--- 0.1.7-5/debian/patches/Handle_non_topdown_bitmaps.patch	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/patches/Handle_non_topdown_bitmaps.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,52 +0,0 @@
-Description: Handle non topdown bitmaps
-Author: Pavel Grunt <pgrunt@redhat.com>
-Date: Tue, 10 Jan 2017 22:54:57 +0100
-Bug-Debian: https://bugs.debian.org/932393
-Last-Update: 2019-07-20
----
- bitmap.js | 20 +++++++++++++-------
- 1 file changed, 13 insertions(+), 7 deletions(-)
-
-diff --git a/bitmap.js b/bitmap.js
-index 03f5127..91278d7 100644
---- a/bitmap.js
-+++ b/bitmap.js
-@@ -26,25 +26,31 @@
- function convert_spice_bitmap_to_web(context, spice_bitmap)
- {
-     var ret;
--    var offset, x;
-+    var offset, x, src_offset = 0, src_dec = 0;
-     var u8 = new Uint8Array(spice_bitmap.data);
-     if (spice_bitmap.format != SPICE_BITMAP_FMT_32BIT &&
-         spice_bitmap.format != SPICE_BITMAP_FMT_RGBA)
-         return undefined;
- 
-+    if (!(spice_bitmap.flags & SPICE_BITMAP_FLAGS_TOP_DOWN))
-+    {
-+        src_offset = (spice_bitmap.y - 1 ) * spice_bitmap.stride;
-+        src_dec = 2 * spice_bitmap.stride;
-+    }
-+
-     ret = context.createImageData(spice_bitmap.x, spice_bitmap.y);
--    for (offset = 0; offset < (spice_bitmap.y * spice_bitmap.stride); )
--        for (x = 0; x < spice_bitmap.x; x++, offset += 4)
-+    for (offset = 0; offset < (spice_bitmap.y * spice_bitmap.stride); src_offset -= src_dec)
-+        for (x = 0; x < spice_bitmap.x; x++, offset += 4, src_offset += 4)
-         {
--            ret.data[offset + 0 ] = u8[offset + 2];
--            ret.data[offset + 1 ] = u8[offset + 1];
--            ret.data[offset + 2 ] = u8[offset + 0];
-+            ret.data[offset + 0 ] = u8[src_offset + 2];
-+            ret.data[offset + 1 ] = u8[src_offset + 1];
-+            ret.data[offset + 2 ] = u8[src_offset + 0];
- 
-             // FIXME - We effectively treat all images as having SPICE_IMAGE_FLAGS_HIGH_BITS_SET
-             if (spice_bitmap.format == SPICE_BITMAP_FMT_32BIT)
-                 ret.data[offset + 3] = 255;
-             else
--                ret.data[offset + 3] = u8[offset];
-+                ret.data[offset + 3] = u8[src_offset];
-         }
- 
-     return ret;
diff -pruN 0.1.7-5/debian/patches/lp1926455-01-add-sc-to-send-ctr-alt-del.patch 0.2.2-0ubuntu3/debian/patches/lp1926455-01-add-sc-to-send-ctr-alt-del.patch
--- 0.1.7-5/debian/patches/lp1926455-01-add-sc-to-send-ctr-alt-del.patch	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/patches/lp1926455-01-add-sc-to-send-ctr-alt-del.patch	2021-05-06 18:03:16.000000000 +0000
@@ -0,0 +1,16 @@
+Description: Add the sc object to sendCtrlAltDel
+ Add the sc object to sendCtrlAltDel because it is otherwise undefined and issues a JS error
+Author: Paul Hodges IV <phodges4@gmail.com>
+Origin: upstream, https://gitlab.freedesktop.org/spice/spice-html5/-/commit/1cc79873609f856d490d3d0ad564f9d2c1708050
+Bug-Ubuntu: https://launchpad.net/bugs/1926455
+--- a/src/inputs.js
++++ b/src/inputs.js
+@@ -190,7 +190,7 @@
+     e.preventDefault();
+ }
+ 
+-function sendCtrlAltDel()
++function sendCtrlAltDel(sc)
+ {
+     if (sc && sc.inputs && sc.inputs.state === "ready"){
+         var key = new Messages.SpiceMsgcKeyDown();
diff -pruN 0.1.7-5/debian/patches/lp1926455-02-add-ctrl-alt-del-with-associated-js-eventlistener.patch 0.2.2-0ubuntu3/debian/patches/lp1926455-02-add-ctrl-alt-del-with-associated-js-eventlistener.patch
--- 0.1.7-5/debian/patches/lp1926455-02-add-ctrl-alt-del-with-associated-js-eventlistener.patch	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/patches/lp1926455-02-add-ctrl-alt-del-with-associated-js-eventlistener.patch	2021-05-06 18:06:24.000000000 +0000
@@ -0,0 +1,24 @@
+Description: addition of ctrl-alt-delete functionality on side navigation, with associated js eventlistener
+ addition of ctrl-alt-delete functionality on side navigation, with associated js eventlistener
+Author: Jonathan Race <racejg@chateaulav.dev>
+Origin: backport, https://gitlab.freedesktop.org/spice/spice-html5/-/commit/56ddb3005e39a9e76670fec9676e667d44167bf3
+Bug-Ubuntu: https://launchpad.net/bugs/1926455
+--- a/spice_auto.html
++++ b/spice_auto.html
+@@ -191,6 +191,7 @@
+             */
+ 
+             connect(undefined);
++            document.getElementById('sendCtrlAltDel').addEventListener('click', function(){ SpiceHtml5.sendCtrlAltDel(sc); });
+         </script>
+ 
+     </head>
+@@ -199,7 +200,7 @@
+ 
+         <div id="login">
+             <span class="logo">SPICE</span>
+-            <button id="sendCtrlAltDelButton" onclick="sendCtrlAltDel();">Send Ctrl-Alt-Delete</button>
++            <button id="sendCtrlAltDel">Send Ctrl-Alt-Delete</button>
+         </div>
+ 
+         <div id="spice-area">
diff -pruN 0.1.7-5/debian/patches/series 0.2.2-0ubuntu3/debian/patches/series
--- 0.1.7-5/debian/patches/series	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/patches/series	2021-05-06 18:07:27.000000000 +0000
@@ -1,3 +1,3 @@
 add-ctrl-alt-del-button.patch
-fix-windows-spice-upside-down.patch
-Handle_non_topdown_bitmaps.patch
+lp1926455-01-add-sc-to-send-ctr-alt-del.patch
+lp1926455-02-add-ctrl-alt-del-with-associated-js-eventlistener.patch
diff -pruN 0.1.7-5/debian/salsa-ci.yml 0.2.2-0ubuntu3/debian/salsa-ci.yml
--- 0.1.7-5/debian/salsa-ci.yml	2020-05-27 15:10:10.000000000 +0000
+++ 0.2.2-0ubuntu3/debian/salsa-ci.yml	1970-01-01 00:00:00.000000000 +0000
@@ -1,3 +0,0 @@
-include:
-  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
-  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
diff -pruN 0.1.7-5/display.js 0.2.2-0ubuntu3/display.js
--- 0.1.7-5/display.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/display.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,1220 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-
-/*----------------------------------------------------------------------------
-**  FIXME: putImageData  does not support Alpha blending
-**           or compositing.  So if we have data in an ImageData
-**           format, we have to draw it onto a context,
-**           and then use drawImage to put it onto the target,
-**           as drawImage does alpha.
-**--------------------------------------------------------------------------*/
-function putImageDataWithAlpha(context, d, x, y)
-{
-    var c = document.createElement("canvas");
-    var t = c.getContext("2d");
-    c.setAttribute('width', d.width);
-    c.setAttribute('height', d.height);
-    t.putImageData(d, 0, 0);
-    context.drawImage(c, x, y, d.width, d.height);
-}
-
-/*----------------------------------------------------------------------------
-**  FIXME: Spice will send an image with '0' alpha when it is intended to
-**           go on a surface w/no alpha.  So in that case, we have to strip
-**           out the alpha.  The test case for this was flux box; in a Xspice
-**           server, right click on the desktop to get the menu; the top bar
-**           doesn't paint/highlight correctly w/out this change.
-**--------------------------------------------------------------------------*/
-function stripAlpha(d)
-{
-    var i;
-    for (i = 0; i < (d.width * d.height * 4); i += 4)
-        d.data[i + 3] = 255;
-}
-
-/*----------------------------------------------------------------------------
-**  SpiceDisplayConn
-**      Drive the Spice Display Channel
-**--------------------------------------------------------------------------*/
-function SpiceDisplayConn()
-{
-    SpiceConn.apply(this, arguments);
-}
-
-SpiceDisplayConn.prototype = Object.create(SpiceConn.prototype);
-SpiceDisplayConn.prototype.process_channel_message = function(msg)
-{
-    if (msg.type == SPICE_MSG_DISPLAY_MODE)
-    {
-        this.known_unimplemented(msg.type, "Display Mode");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_MARK)
-    {
-        // FIXME - DISPLAY_MARK not implemented (may be hard or impossible)
-        this.known_unimplemented(msg.type, "Display Mark");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_RESET)
-    {
-        DEBUG > 2 && console.log("Display reset");
-        this.surfaces[this.primary_surface].canvas.context.restore();
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_COPY)
-    {
-        var draw_copy = new SpiceMsgDisplayDrawCopy(msg.data);
-
-        DEBUG > 1 && this.log_draw("DrawCopy", draw_copy);
-
-        if (! draw_copy.base.box.is_same_size(draw_copy.data.src_area))
-            this.log_warn("FIXME: DrawCopy src_area is a different size than base.box; we do not handle that yet.");
-        if (draw_copy.base.clip.type != SPICE_CLIP_TYPE_NONE)
-            this.log_warn("FIXME: DrawCopy we don't handle clipping yet");
-        if (draw_copy.data.rop_descriptor != SPICE_ROPD_OP_PUT)
-            this.log_warn("FIXME: DrawCopy we don't handle ropd type: " + draw_copy.data.rop_descriptor);
-        if (draw_copy.data.mask.flags)
-            this.log_warn("FIXME: DrawCopy we don't handle mask flag: " + draw_copy.data.mask.flags);
-        if (draw_copy.data.mask.bitmap)
-            this.log_warn("FIXME: DrawCopy we don't handle mask");
-
-        if (draw_copy.data && draw_copy.data.src_bitmap)
-        {
-            if (draw_copy.data.src_bitmap.descriptor.flags &&
-                draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_CACHE_ME &&
-                draw_copy.data.src_bitmap.descriptor.flags != SPICE_IMAGE_FLAGS_HIGH_BITS_SET)
-            {
-                this.log_warn("FIXME: DrawCopy unhandled image flags: " + draw_copy.data.src_bitmap.descriptor.flags);
-                DEBUG <= 1 && this.log_draw("DrawCopy", draw_copy);
-            }
-
-            if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_QUIC)
-            {
-                var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
-                if (! draw_copy.data.src_bitmap.quic)
-                {
-                    this.log_warn("FIXME: DrawCopy could not handle this QUIC file.");
-                    return false;
-                }
-                var source_img = convert_spice_quic_to_web(canvas.context,
-                                        draw_copy.data.src_bitmap.quic);
-
-                return this.draw_copy_helper(
-                    { base: draw_copy.base,
-                      src_area: draw_copy.data.src_area,
-                      image_data: source_img,
-                      tag: "copyquic." + draw_copy.data.src_bitmap.quic.type,
-                      has_alpha: (draw_copy.data.src_bitmap.quic.type == QUIC_IMAGE_TYPE_RGBA ? true : false) ,
-                      descriptor : draw_copy.data.src_bitmap.descriptor
-                    });
-            }
-            else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE ||
-                    draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS)
-            {
-                if (! this.cache || ! this.cache[draw_copy.data.src_bitmap.descriptor.id])
-                {
-                    this.log_warn("FIXME: DrawCopy did not find image id " + draw_copy.data.src_bitmap.descriptor.id + " in cache.");
-                    return false;
-                }
-
-                return this.draw_copy_helper(
-                    { base: draw_copy.base,
-                      src_area: draw_copy.data.src_area,
-                      image_data: this.cache[draw_copy.data.src_bitmap.descriptor.id],
-                      tag: "copycache." + draw_copy.data.src_bitmap.descriptor.id, 
-                      has_alpha: true, /* FIXME - may want this to be false... */
-                      descriptor : draw_copy.data.src_bitmap.descriptor
-                    });
-
-                /* FIXME - LOSSLESS CACHE ramifications not understood or handled */
-            }
-            else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_SURFACE)
-            {
-                var source_context = this.surfaces[draw_copy.data.src_bitmap.surface_id].canvas.context;
-                var target_context = this.surfaces[draw_copy.base.surface_id].canvas.context;
-
-                var source_img = source_context.getImageData(
-                        draw_copy.data.src_area.left, draw_copy.data.src_area.top,
-                        draw_copy.data.src_area.right - draw_copy.data.src_area.left,
-                        draw_copy.data.src_area.bottom - draw_copy.data.src_area.top);
-                var computed_src_area = new SpiceRect;
-                computed_src_area.top = computed_src_area.left = 0;
-                computed_src_area.right = source_img.width;
-                computed_src_area.bottom = source_img.height;
-
-                /* FIXME - there is a potential optimization here.
-                           That is, if the surface is from 0,0, and
-                           both surfaces are alpha surfaces, you should
-                           be able to just do a drawImage, which should
-                           save time.  */
-
-                return this.draw_copy_helper(
-                    { base: draw_copy.base,
-                      src_area: computed_src_area,
-                      image_data: source_img,
-                      tag: "copysurf." + draw_copy.data.src_bitmap.surface_id,
-                      has_alpha: this.surfaces[draw_copy.data.src_bitmap.surface_id].format == SPICE_SURFACE_FMT_32_xRGB ? false : true,
-                      descriptor : draw_copy.data.src_bitmap.descriptor
-                    });
-            }
-            else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG)
-            {
-                if (! draw_copy.data.src_bitmap.jpeg)
-                {
-                    this.log_warn("FIXME: DrawCopy could not handle this JPEG file.");
-                    return false;
-                }
-
-                // FIXME - how lame is this.  Be have it in binary format, and we have
-                //         to put it into string to get it back into jpeg.  Blech.
-                var tmpstr = "data:image/jpeg,";
-                var img = new Image;
-                var i;
-                var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg.data);
-                for (i = 0; i < qdv.length; i++)
-                {
-                    tmpstr +=  '%';
-                    if (qdv[i] < 16)
-                        tmpstr += '0';
-                    tmpstr += qdv[i].toString(16);
-                }
-
-                img.o = 
-                    { base: draw_copy.base,
-                      tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
-                      descriptor : draw_copy.data.src_bitmap.descriptor,
-                      sc : this,
-                    };
-                img.onload = handle_draw_jpeg_onload;
-                img.src = tmpstr;
-
-                return true;
-            }
-            else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA)
-            {
-                if (! draw_copy.data.src_bitmap.jpeg_alpha)
-                {
-                    this.log_warn("FIXME: DrawCopy could not handle this JPEG ALPHA file.");
-                    return false;
-                }
-
-                // FIXME - how lame is this.  Be have it in binary format, and we have
-                //         to put it into string to get it back into jpeg.  Blech.
-                var tmpstr = "data:image/jpeg,";
-                var img = new Image;
-                var i;
-                var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg_alpha.data);
-                for (i = 0; i < qdv.length; i++)
-                {
-                    tmpstr +=  '%';
-                    if (qdv[i] < 16)
-                        tmpstr += '0';
-                    tmpstr += qdv[i].toString(16);
-                }
-
-                img.o = 
-                    { base: draw_copy.base,
-                      tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
-                      descriptor : draw_copy.data.src_bitmap.descriptor,
-                      sc : this,
-                    };
-
-                if (this.surfaces[draw_copy.base.surface_id].format == SPICE_SURFACE_FMT_32_ARGB)
-                {
-
-                    var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
-                    img.alpha_img = convert_spice_lz_to_web(canvas.context,
-                                            draw_copy.data.src_bitmap.jpeg_alpha.alpha);
-                }
-                img.onload = handle_draw_jpeg_onload;
-                img.src = tmpstr;
-
-                return true;
-            }
-            else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_BITMAP)
-            {
-                var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
-                if (! draw_copy.data.src_bitmap.bitmap)
-                {
-                    this.log_err("null bitmap");
-                    return false;
-                }
-
-                var source_img = convert_spice_bitmap_to_web(canvas.context,
-                                        draw_copy.data.src_bitmap.bitmap);
-                if (! source_img)
-                {
-                    this.log_warn("FIXME: Unable to interpret bitmap of format: " + 
-                        draw_copy.data.src_bitmap.bitmap.format);
-                    return false;
-                }
-
-                return this.draw_copy_helper(
-                    { base: draw_copy.base,
-                      src_area: draw_copy.data.src_area,
-                      image_data: source_img,
-                      tag: "bitmap." + draw_copy.data.src_bitmap.bitmap.format,
-                      has_alpha: draw_copy.data.src_bitmap.bitmap == SPICE_BITMAP_FMT_32BIT ? false : true,
-                      descriptor : draw_copy.data.src_bitmap.descriptor
-                    });
-            }
-            else if (draw_copy.data.src_bitmap.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB)
-            {
-                var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
-                if (! draw_copy.data.src_bitmap.lz_rgb)
-                {
-                    this.log_err("null lz_rgb ");
-                    return false;
-                }
-
-                if (draw_copy.data.src_bitmap.lz_rgb.top_down != 1)
-                    this.log_warn("FIXME: Implement non top down support for lz_rgb");
-
-                var source_img = convert_spice_lz_to_web(canvas.context,
-                                            draw_copy.data.src_bitmap.lz_rgb);
-                if (! source_img)
-                {
-                    this.log_warn("FIXME: Unable to interpret bitmap of type: " + 
-                        draw_copy.data.src_bitmap.lz_rgb.type);
-                    return false;
-                }
-
-                return this.draw_copy_helper(
-                    { base: draw_copy.base,
-                      src_area: draw_copy.data.src_area,
-                      image_data: source_img,
-                      tag: "lz_rgb." + draw_copy.data.src_bitmap.lz_rgb.type,
-                      has_alpha: draw_copy.data.src_bitmap.lz_rgb.type == LZ_IMAGE_TYPE_RGBA ? true : false ,
-                      descriptor : draw_copy.data.src_bitmap.descriptor
-                    });
-            }
-            else
-            {
-                this.log_warn("FIXME: DrawCopy unhandled image type: " + draw_copy.data.src_bitmap.descriptor.type);
-                this.log_draw("DrawCopy", draw_copy);
-                return false;
-            }
-        }
-
-        this.log_warn("FIXME: DrawCopy no src_bitmap.");
-        return false;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_FILL)
-    {
-        var draw_fill = new SpiceMsgDisplayDrawFill(msg.data);
-
-        DEBUG > 1 && this.log_draw("DrawFill", draw_fill);
-
-        if (draw_fill.data.rop_descriptor != SPICE_ROPD_OP_PUT)
-            this.log_warn("FIXME: DrawFill we don't handle ropd type: " + draw_fill.data.rop_descriptor);
-        if (draw_fill.data.mask.flags)
-            this.log_warn("FIXME: DrawFill we don't handle mask flag: " + draw_fill.data.mask.flags);
-        if (draw_fill.data.mask.bitmap)
-            this.log_warn("FIXME: DrawFill we don't handle mask");
-
-        if (draw_fill.data.brush.type == SPICE_BRUSH_TYPE_SOLID)
-        {
-            // FIXME - do brushes ever have alpha?
-            var color = draw_fill.data.brush.color & 0xffffff;
-            var color_str = "rgb(" + (color >> 16) + ", " + ((color >> 8) & 0xff) + ", " + (color & 0xff) + ")";
-            this.surfaces[draw_fill.base.surface_id].canvas.context.fillStyle = color_str;
-
-            this.surfaces[draw_fill.base.surface_id].canvas.context.fillRect(
-                draw_fill.base.box.left, draw_fill.base.box.top,
-                draw_fill.base.box.right - draw_fill.base.box.left,
-                draw_fill.base.box.bottom - draw_fill.base.box.top);
-
-            if (DUMP_DRAWS && this.parent.dump_id)
-            {
-                var debug_canvas = document.createElement("canvas");
-                debug_canvas.setAttribute('width', this.surfaces[draw_fill.base.surface_id].canvas.width);
-                debug_canvas.setAttribute('height', this.surfaces[draw_fill.base.surface_id].canvas.height);
-                debug_canvas.setAttribute('id', "fillbrush." + draw_fill.base.surface_id + "." + this.surfaces[draw_fill.base.surface_id].draw_count);
-                debug_canvas.getContext("2d").fillStyle = color_str;
-                debug_canvas.getContext("2d").fillRect(
-                    draw_fill.base.box.left, draw_fill.base.box.top,
-                    draw_fill.base.box.right - draw_fill.base.box.left,
-                    draw_fill.base.box.bottom - draw_fill.base.box.top);
-                document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
-            }
-                
-            this.surfaces[draw_fill.base.surface_id].draw_count++;
-
-        }
-        else
-        {
-            this.log_warn("FIXME: DrawFill can't handle brush type: " + draw_fill.data.brush.type);
-        }
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_OPAQUE)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Opaque");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_BLEND)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Blend");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_BLACKNESS)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Blackness");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_WHITENESS)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Whiteness");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_INVERS)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Invers");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_ROP3)
-    {
-        this.known_unimplemented(msg.type, "Display Draw ROP3");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_STROKE)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Stroke");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_TRANSPARENT)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Transparent");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Alpha Blend");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_COPY_BITS)
-    {
-        var copy_bits = new SpiceMsgDisplayCopyBits(msg.data);
-
-        DEBUG > 1 && this.log_draw("CopyBits", copy_bits);
-
-        var source_canvas = this.surfaces[copy_bits.base.surface_id].canvas;
-        var source_context = source_canvas.context;
-
-        var width = source_canvas.width - copy_bits.src_pos.x;
-        var height = source_canvas.height - copy_bits.src_pos.y;
-        if (width > (copy_bits.base.box.right - copy_bits.base.box.left))
-            width = copy_bits.base.box.right - copy_bits.base.box.left;
-        if (height > (copy_bits.base.box.bottom - copy_bits.base.box.top))
-            height = copy_bits.base.box.bottom - copy_bits.base.box.top;
-
-        var source_img = source_context.getImageData(
-                copy_bits.src_pos.x, copy_bits.src_pos.y, width, height);
-        //source_context.putImageData(source_img, copy_bits.base.box.left, copy_bits.base.box.top);
-        putImageDataWithAlpha(source_context, source_img, copy_bits.base.box.left, copy_bits.base.box.top);
-
-        if (DUMP_DRAWS && this.parent.dump_id)
-        {
-            var debug_canvas = document.createElement("canvas");
-            debug_canvas.setAttribute('width', width);
-            debug_canvas.setAttribute('height', height);
-            debug_canvas.setAttribute('id', "copybits" + copy_bits.base.surface_id + "." + this.surfaces[copy_bits.base.surface_id].draw_count);
-            debug_canvas.getContext("2d").putImageData(source_img, 0, 0);
-            document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
-        }
-
-
-        this.surfaces[copy_bits.base.surface_id].draw_count++;
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS)
-    {
-        this.known_unimplemented(msg.type, "Display Inval All Pixmaps");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_INVAL_PALETTE)
-    {
-        this.known_unimplemented(msg.type, "Display Inval Palette");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES)
-    {
-        this.known_unimplemented(msg.type, "Inval All Palettes");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_SURFACE_CREATE)
-    {
-        if (! ("surfaces" in this))
-            this.surfaces = [];
-
-        var m = new SpiceMsgSurfaceCreate(msg.data);
-        DEBUG > 1 && console.log(this.type + ": MsgSurfaceCreate id " + m.surface.surface_id 
-                                    + "; " + m.surface.width + "x" + m.surface.height
-                                    + "; format " + m.surface.format 
-                                    + "; flags " + m.surface.flags);
-        if (m.surface.format != SPICE_SURFACE_FMT_32_xRGB &&
-            m.surface.format != SPICE_SURFACE_FMT_32_ARGB)
-        {
-            this.log_warn("FIXME: cannot handle surface format " + m.surface.format + " yet.");
-            return false;
-        }
-
-        var canvas = document.createElement("canvas");
-        canvas.setAttribute('width', m.surface.width);
-        canvas.setAttribute('height', m.surface.height);
-        canvas.setAttribute('id', "spice_surface_" + m.surface.surface_id);
-        canvas.setAttribute('tabindex', m.surface.surface_id);
-        canvas.context = canvas.getContext("2d");
-
-        if (DUMP_CANVASES && this.parent.dump_id)
-            document.getElementById(this.parent.dump_id).appendChild(canvas);
-
-        m.surface.canvas = canvas;
-        m.surface.draw_count = 0;
-        this.surfaces[m.surface.surface_id] = m.surface;
-
-        if (m.surface.flags & SPICE_SURFACE_FLAGS_PRIMARY)
-        {
-            this.primary_surface = m.surface.surface_id;
-
-            /* This .save() is done entirely to enable SPICE_MSG_DISPLAY_RESET */
-            canvas.context.save();
-            document.getElementById(this.parent.screen_id).appendChild(canvas);
-
-            /* We're going to leave width dynamic, but correctly set the height */
-            document.getElementById(this.parent.screen_id).style.height = m.surface.height + "px";
-            this.hook_events();
-        }
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_SURFACE_DESTROY)
-    {
-        var m = new SpiceMsgSurfaceDestroy(msg.data);
-        DEBUG > 1 && console.log(this.type + ": MsgSurfaceDestroy id " + m.surface_id);
-        this.delete_surface(m.surface_id);
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_STREAM_CREATE)
-    {
-        var m = new SpiceMsgDisplayStreamCreate(msg.data);
-        DEBUG > 1 && console.log(this.type + ": MsgStreamCreate id" + m.id);
-        if (!this.streams)
-            this.streams = new Array();
-        if (this.streams[m.id])
-            console.log("Stream " + m.id + " already exists");
-        else
-            this.streams[m.id] = m;
-
-        if (m.codec_type == SPICE_VIDEO_CODEC_TYPE_VP8)
-        {
-            var media = new MediaSource();
-            var v = document.createElement("video");
-            v.src = window.URL.createObjectURL(media);
-
-            v.setAttribute('autoplay', true);
-            v.setAttribute('width', m.stream_width);
-            v.setAttribute('height', m.stream_height);
-
-            var left = m.dest.left;
-            var top = m.dest.top;
-            if (this.surfaces[m.surface_id] !== undefined)
-            {
-                left += this.surfaces[m.surface_id].canvas.offsetLeft;
-                top += this.surfaces[m.surface_id].canvas.offsetTop;
-            }
-            document.getElementById(this.parent.screen_id).appendChild(v);
-            v.setAttribute('style', "position: absolute; top:" + top + "px; left:" + left + "px;");
-
-            media.addEventListener('sourceopen', handle_video_source_open, false);
-            media.addEventListener('sourceended', handle_video_source_ended, false);
-            media.addEventListener('sourceclosed', handle_video_source_closed, false);
-
-            this.streams[m.id].video = v;
-            this.streams[m.id].media = media;
-
-            media.stream = this.streams[m.id];
-            media.spiceconn = this;
-            v.spice_stream = this.streams[m.id];
-        }
-        else if (m.codec_type != SPICE_VIDEO_CODEC_TYPE_MJPEG)
-            console.log("Unhandled stream codec: "+m.codec_type);
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA ||
-        msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED)
-    {
-        var m;
-        if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED)
-            m = new SpiceMsgDisplayStreamDataSized(msg.data);
-        else
-            m = new SpiceMsgDisplayStreamData(msg.data);
-
-        if (!this.streams[m.base.id])
-        {
-            console.log("no stream for data");
-            return false;
-        }
-
-        var time_until_due = m.base.multi_media_time - this.parent.relative_now();
-
-        if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG)
-            process_mjpeg_stream_data(this, m, time_until_due);
-
-        if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_VP8)
-            process_video_stream_data(this.streams[m.base.id], m);
-
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT)
-    {
-        var m = new SpiceMsgDisplayStreamActivateReport(msg.data);
-
-        var report = new SpiceMsgcDisplayStreamReport(m.stream_id, m.unique_id);
-        if (this.streams[m.stream_id])
-        {
-            this.streams[m.stream_id].report = report;
-            this.streams[m.stream_id].max_window_size = m.max_window_size;
-            this.streams[m.stream_id].timeout_ms = m.timeout_ms
-        }
-
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_STREAM_CLIP)
-    {
-        var m = new SpiceMsgDisplayStreamClip(msg.data);
-        DEBUG > 1 && console.log(this.type + ": MsgStreamClip id" + m.id);
-        this.streams[m.id].clip = m.clip;
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_STREAM_DESTROY)
-    {
-        var m = new SpiceMsgDisplayStreamDestroy(msg.data);
-        DEBUG > 1 && console.log(this.type + ": MsgStreamDestroy id" + m.id);
-
-        if (this.streams[m.id].codec_type == SPICE_VIDEO_CODEC_TYPE_VP8)
-        {
-            document.getElementById(this.parent.screen_id).removeChild(this.streams[m.id].video);
-            this.streams[m.id].source_buffer = null;
-            this.streams[m.id].media = null;
-            this.streams[m.id].video = null;
-        }
-        this.streams[m.id] = undefined;
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL)
-    {
-        this.known_unimplemented(msg.type, "Display Stream Destroy All");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_INVAL_LIST)
-    {
-        var m = new SpiceMsgDisplayInvalList(msg.data);
-        var i;
-        DEBUG > 1 && console.log(this.type + ": MsgInvalList " + m.count + " items");
-        for (i = 0; i < m.count; i++)
-            if (this.cache[m.resources[i].id] != undefined)
-                delete this.cache[m.resources[i].id];
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_MONITORS_CONFIG)
-    {
-        this.known_unimplemented(msg.type, "Display Monitors Config");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_DISPLAY_DRAW_COMPOSITE)
-    {
-        this.known_unimplemented(msg.type, "Display Draw Composite");
-        return true;
-    }
-
-    return false;
-}
-
-SpiceDisplayConn.prototype.delete_surface = function(surface_id)
-{
-    var canvas = document.getElementById("spice_surface_" + surface_id);
-    if (DUMP_CANVASES && this.parent.dump_id)
-        document.getElementById(this.parent.dump_id).removeChild(canvas);
-    if (this.primary_surface == surface_id)
-    {
-        this.unhook_events();
-        this.primary_surface = undefined;
-        document.getElementById(this.parent.screen_id).removeChild(canvas);
-    }
-
-    delete this.surfaces[surface_id];
-}
-
-
-SpiceDisplayConn.prototype.draw_copy_helper = function(o)
-{
-
-    var canvas = this.surfaces[o.base.surface_id].canvas;
-    if (o.has_alpha)
-    {
-        /* FIXME - This is based on trial + error, not a serious thoughtful
-                   analysis of what Spice requires.  See display.js for more. */
-        if (this.surfaces[o.base.surface_id].format == SPICE_SURFACE_FMT_32_xRGB)
-        {
-            stripAlpha(o.image_data);
-            canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
-        }
-        else
-            putImageDataWithAlpha(canvas.context, o.image_data,
-                    o.base.box.left, o.base.box.top);
-    }
-    else
-        canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
-
-    if (o.src_area.left > 0 || o.src_area.top > 0)
-    {
-        this.log_warn("FIXME: DrawCopy not shifting draw copies just yet...");
-    }
-
-    if (o.descriptor && (o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
-    {
-        if (! ("cache" in this))
-            this.cache = {};
-        this.cache[o.descriptor.id] = o.image_data;
-    }
-
-    if (DUMP_DRAWS && this.parent.dump_id)
-    {
-        var debug_canvas = document.createElement("canvas");
-        debug_canvas.setAttribute('width', o.image_data.width);
-        debug_canvas.setAttribute('height', o.image_data.height);
-        debug_canvas.setAttribute('id', o.tag + "." +
-            this.surfaces[o.base.surface_id].draw_count + "." +
-            o.base.surface_id + "@" + o.base.box.left + "x" +  o.base.box.top);
-        debug_canvas.getContext("2d").putImageData(o.image_data, 0, 0);
-        document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
-    }
-
-    this.surfaces[o.base.surface_id].draw_count++;
-
-    return true;
-}
-
-
-SpiceDisplayConn.prototype.log_draw = function(prefix, draw)
-{
-    var str = prefix + "." + draw.base.surface_id + "." + this.surfaces[draw.base.surface_id].draw_count + ": ";
-    str += "base.box " + draw.base.box.left + ", " + draw.base.box.top + " to " + 
-                           draw.base.box.right + ", " + draw.base.box.bottom;
-    str += "; clip.type " + draw.base.clip.type;
-
-    if (draw.data)
-    {
-        if (draw.data.src_area)
-            str += "; src_area " + draw.data.src_area.left + ", " + draw.data.src_area.top + " to "
-                                 + draw.data.src_area.right + ", " + draw.data.src_area.bottom;
-
-        if (draw.data.src_bitmap && draw.data.src_bitmap != null)
-        {
-            str += "; src_bitmap id: " + draw.data.src_bitmap.descriptor.id;
-            str += "; src_bitmap width " + draw.data.src_bitmap.descriptor.width + ", height " + draw.data.src_bitmap.descriptor.height;
-            str += "; src_bitmap type " + draw.data.src_bitmap.descriptor.type + ", flags " + draw.data.src_bitmap.descriptor.flags;
-            if (draw.data.src_bitmap.surface_id !== undefined)
-                str += "; src_bitmap surface_id " + draw.data.src_bitmap.surface_id;
-            if (draw.data.src_bitmap.quic)
-                str += "; QUIC type " + draw.data.src_bitmap.quic.type + 
-                        "; width " + draw.data.src_bitmap.quic.width + 
-                        "; height " + draw.data.src_bitmap.quic.height ;
-            if (draw.data.src_bitmap.lz_rgb)
-                str += "; LZ_RGB length " + draw.data.src_bitmap.lz_rgb.length +
-                       "; magic " + draw.data.src_bitmap.lz_rgb.magic + 
-                       "; version 0x" + draw.data.src_bitmap.lz_rgb.version.toString(16) +
-                       "; type " + draw.data.src_bitmap.lz_rgb.type +
-                       "; width " + draw.data.src_bitmap.lz_rgb.width +
-                       "; height " + draw.data.src_bitmap.lz_rgb.height +
-                       "; stride " + draw.data.src_bitmap.lz_rgb.stride +
-                       "; top down " + draw.data.src_bitmap.lz_rgb.top_down;
-        }
-        else
-            str += "; src_bitmap is null";
-
-        if (draw.data.brush)
-        {
-            if (draw.data.brush.type == SPICE_BRUSH_TYPE_SOLID)
-                str += "; brush.color 0x" + draw.data.brush.color.toString(16);
-            if (draw.data.brush.type == SPICE_BRUSH_TYPE_PATTERN)
-            {
-                str += "; brush.pat ";
-                if (draw.data.brush.pattern.pat != null)
-                    str += "[SpiceImage]";
-                else
-                    str += "[null]";
-                str += " at " + draw.data.brush.pattern.pos.x + ", " + draw.data.brush.pattern.pos.y;
-            }
-        }
-
-        str += "; rop_descriptor " + draw.data.rop_descriptor;
-        if (draw.data.scale_mode !== undefined)
-            str += "; scale_mode " + draw.data.scale_mode;
-        str += "; mask.flags " + draw.data.mask.flags;
-        str += "; mask.pos " + draw.data.mask.pos.x + ", " + draw.data.mask.pos.y;
-        if (draw.data.mask.bitmap != null)
-        {
-            str += "; mask.bitmap width " + draw.data.mask.bitmap.descriptor.width + ", height " + draw.data.mask.bitmap.descriptor.height;
-            str += "; mask.bitmap type " + draw.data.mask.bitmap.descriptor.type + ", flags " + draw.data.mask.bitmap.descriptor.flags;
-        }
-        else
-            str += "; mask.bitmap is null";
-    }
-
-    console.log(str);
-}
-
-SpiceDisplayConn.prototype.hook_events = function()
-{
-    if (this.primary_surface !== undefined)
-    {
-        var canvas = this.surfaces[this.primary_surface].canvas;
-        canvas.sc = this.parent;
-        canvas.addEventListener('mousemove', handle_mousemove);
-        canvas.addEventListener('mousedown', handle_mousedown);
-        canvas.addEventListener('contextmenu', handle_contextmenu);
-        canvas.addEventListener('mouseup', handle_mouseup);
-        canvas.addEventListener('keydown', handle_keydown);
-        canvas.addEventListener('keyup', handle_keyup);
-        canvas.addEventListener('mouseout', handle_mouseout);
-        canvas.addEventListener('mouseover', handle_mouseover);
-        canvas.addEventListener('wheel', handle_mousewheel);
-        canvas.focus();
-    }
-}
-
-SpiceDisplayConn.prototype.unhook_events = function()
-{
-    if (this.primary_surface !== undefined)
-    {
-        var canvas = this.surfaces[this.primary_surface].canvas;
-        canvas.removeEventListener('mousemove', handle_mousemove);
-        canvas.removeEventListener('mousedown', handle_mousedown);
-        canvas.removeEventListener('contextmenu', handle_contextmenu);
-        canvas.removeEventListener('mouseup', handle_mouseup);
-        canvas.removeEventListener('keydown', handle_keydown);
-        canvas.removeEventListener('keyup', handle_keyup);
-        canvas.removeEventListener('mouseout', handle_mouseout);
-        canvas.removeEventListener('mouseover', handle_mouseover);
-        canvas.removeEventListener('wheel', handle_mousewheel);
-    }
-}
-
-
-SpiceDisplayConn.prototype.destroy_surfaces = function()
-{
-    for (var s in this.surfaces)
-    {
-        this.delete_surface(this.surfaces[s].surface_id);
-    }
-
-    this.surfaces = undefined;
-}
-
-
-function handle_mouseover(e)
-{
-    this.focus();
-}
-
-function handle_mouseout(e)
-{
-    if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor)
-        this.sc.cursor.spice_simulated_cursor.style.display = 'none';
-    this.blur();
-}
-
-function handle_draw_jpeg_onload()
-{
-    var temp_canvas = null;
-    var context;
-
-    /*------------------------------------------------------------
-    ** FIXME:
-    **  The helper should be extended to be able to handle actual HtmlImageElements
-    **  ...and the cache should be modified to do so as well
-    **----------------------------------------------------------*/
-    if (this.o.sc.surfaces[this.o.base.surface_id] === undefined)
-    {
-        // This can happen; if the jpeg image loads after our surface
-        //  has been destroyed (e.g. open a menu, close it quickly),
-        //  we'll find we have no surface.  
-        DEBUG > 2 && this.o.sc.log_info("Discarding jpeg; presumed lost surface " + this.o.base.surface_id);
-        temp_canvas = document.createElement("canvas");
-        temp_canvas.setAttribute('width', this.o.base.box.right);
-        temp_canvas.setAttribute('height', this.o.base.box.bottom);
-        context = temp_canvas.getContext("2d");
-    }
-    else
-        context = this.o.sc.surfaces[this.o.base.surface_id].canvas.context;
-
-    if (this.alpha_img)
-    {
-        var c = document.createElement("canvas");
-        var t = c.getContext("2d");
-        c.setAttribute('width', this.alpha_img.width);
-        c.setAttribute('height', this.alpha_img.height);
-        t.putImageData(this.alpha_img, 0, 0);
-        t.globalCompositeOperation = 'source-in';
-        t.drawImage(this, 0, 0);
-     
-        context.drawImage(c, this.o.base.box.left, this.o.base.box.top);
-
-        if (this.o.descriptor && 
-            (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
-        {
-            if (! ("cache" in this.o.sc))
-                this.o.sc.cache = {};
-
-            this.o.sc.cache[this.o.descriptor.id] = 
-                t.getImageData(0, 0,
-                    this.alpha_img.width,
-                    this.alpha_img.height);
-        }
-    }
-    else
-    {
-        context.drawImage(this, this.o.base.box.left, this.o.base.box.top);
-
-        // Give the Garbage collector a clue to recycle this; avoids
-        //  fairly massive memory leaks during video playback
-        this.src = null;
-
-        if (this.o.descriptor && 
-            (this.o.descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME))
-        {
-            if (! ("cache" in this.o.sc))
-                this.o.sc.cache = {};
-
-            this.o.sc.cache[this.o.descriptor.id] = 
-                context.getImageData(this.o.base.box.left, this.o.base.box.top,
-                    this.o.base.box.right - this.o.base.box.left,
-                    this.o.base.box.bottom - this.o.base.box.top);
-        }
-    }
-
-    if (temp_canvas == null)
-    {
-        if (DUMP_DRAWS && this.o.sc.parent.dump_id)
-        {
-            var debug_canvas = document.createElement("canvas");
-            debug_canvas.setAttribute('id', this.o.tag + "." +
-                this.o.sc.surfaces[this.o.base.surface_id].draw_count + "." +
-                this.o.base.surface_id + "@" + this.o.base.box.left + "x" +  this.o.base.box.top);
-            debug_canvas.getContext("2d").drawImage(this, 0, 0);
-            document.getElementById(this.o.sc.parent.dump_id).appendChild(debug_canvas);
-        }
-
-        this.o.sc.surfaces[this.o.base.surface_id].draw_count++;
-    }
-
-    if ("report" in this.o.sc.streams[this.o.id])
-            process_stream_data_report(this.o.sc, this.o.id, this.o.msg_mmtime, this.o.msg_mmtime - this.o.sc.parent.relative_now())
-}
-
-function process_mjpeg_stream_data(sc, m, time_until_due)
-{
-    if (time_until_due < 0)
-    {
-        if ("report" in sc.streams[m.base.id])
-            sc.streams[m.base.id].report.num_drops++;
-        return;
-    }
-
-    var tmpstr = "data:image/jpeg,";
-    var img = new Image;
-    var i;
-    for (i = 0; i < m.data.length; i++)
-    {
-        tmpstr +=  '%';
-        if (m.data[i] < 16)
-        tmpstr += '0';
-        tmpstr += m.data[i].toString(16);
-    }
-    var strm_base = new SpiceMsgDisplayBase();
-    strm_base.surface_id = sc.streams[m.base.id].surface_id;
-    strm_base.box = m.dest || sc.streams[m.base.id].dest;
-    strm_base.clip = sc.streams[m.base.id].clip;
-    img.o =
-        { base: strm_base,
-          tag: "mjpeg." + m.base.id,
-          descriptor: null,
-          sc : sc,
-          id : m.base.id,
-          msg_mmtime : m.base.multi_media_time,
-        };
-    img.onload = handle_draw_jpeg_onload;
-    img.src = tmpstr;
-}
-
-function process_stream_data_report(sc, id, msg_mmtime, time_until_due)
-{
-    sc.streams[id].report.num_frames++;
-    if (sc.streams[id].report.start_frame_mm_time == 0)
-        sc.streams[id].report.start_frame_mm_time = msg_mmtime;
-
-    if (sc.streams[id].report.num_frames > sc.streams[id].max_window_size ||
-        (msg_mmtime - sc.streams[id].report.start_frame_mm_time) > sc.streams[id].timeout_ms)
-    {
-        sc.streams[id].report.end_frame_mm_time = msg_mmtime;
-        sc.streams[id].report.last_frame_delay = time_until_due;
-
-        var msg = new SpiceMiniData();
-        msg.build_msg(SPICE_MSGC_DISPLAY_STREAM_REPORT, sc.streams[id].report);
-        sc.send_msg(msg);
-
-        sc.streams[id].report.start_frame_mm_time = 0;
-        sc.streams[id].report.num_frames = 0;
-        sc.streams[id].report.num_drops = 0;
-    }
-}
-
-function handle_video_source_open(e)
-{
-    var stream = this.stream;
-    var p = this.spiceconn;
-
-    if (stream.source_buffer)
-        return;
-
-    var s = this.addSourceBuffer(SPICE_VP8_CODEC);
-    if (! s)
-    {
-        p.log_err('Codec ' + SPICE_VP8_CODEC + ' not available.');
-        return;
-    }
-
-    stream.source_buffer = s;
-    s.spiceconn = p;
-    s.stream = stream;
-
-    stream.queue = new Array();
-    stream.start_time = 0;
-    stream.cluster_time = 0;
-
-    listen_for_video_events(stream);
-
-    var h = new webm_Header();
-    var te = new webm_VideoTrackEntry(this.stream.stream_width, this.stream.stream_height);
-    var t = new webm_Tracks(te);
-
-    var mb = new ArrayBuffer(h.buffer_size() + t.buffer_size())
-
-    var b = h.to_buffer(mb);
-    t.to_buffer(mb, b);
-
-    s.addEventListener('error', handle_video_buffer_error, false);
-    s.addEventListener('updateend', handle_append_video_buffer_done, false);
-
-    append_video_buffer(s, mb);
-}
-
-function handle_video_source_ended(e)
-{
-    var p = this.spiceconn;
-    p.log_err('Video source unexpectedly ended.');
-}
-
-function handle_video_source_closed(e)
-{
-    var p = this.spiceconn;
-    p.log_err('Video source unexpectedly closed.');
-}
-
-function append_video_buffer(sb, mb)
-{
-    try
-    {
-        sb.stream.append_okay = false;
-        sb.appendBuffer(mb);
-    }
-    catch (e)
-    {
-        var p = sb.spiceconn;
-        p.log_err("Error invoking appendBuffer: " + e.message);
-    }
-}
-
-function handle_append_video_buffer_done(e)
-{
-    var stream = this.stream;
-
-    if (stream.current_frame && "report" in stream)
-    {
-        var sc = this.stream.media.spiceconn;
-        var t = this.stream.current_frame.msg_mmtime;
-        process_stream_data_report(sc, stream.id, t, t - sc.parent.relative_now());
-    }
-
-    if (stream.queue.length > 0)
-    {
-        stream.current_frame = stream.queue.shift();
-        append_video_buffer(stream.source_buffer, stream.current_frame.mb);
-    }
-    else
-    {
-        stream.append_okay = true;
-    }
-}
-
-function handle_video_buffer_error(e)
-{
-    var p = this.spiceconn;
-    p.log_err('source_buffer error ' + e.message);
-}
-
-function push_or_queue(stream, msg, mb)
-{
-    var frame =
-    {
-        msg_mmtime : msg.base.multi_media_time,
-    };
-
-    if (stream.append_okay)
-    {
-        stream.current_frame = frame;
-        append_video_buffer(stream.source_buffer, mb);
-    }
-    else
-    {
-        frame.mb = mb;
-        stream.queue.push(frame);
-    }
-}
-
-function video_simple_block(stream, msg, keyframe)
-{
-    var simple = new webm_SimpleBlock(msg.base.multi_media_time - stream.cluster_time, msg.data, keyframe);
-    var mb = new ArrayBuffer(simple.buffer_size());
-    simple.to_buffer(mb);
-
-    push_or_queue(stream, msg, mb);
-}
-
-function new_video_cluster(stream, msg)
-{
-    stream.cluster_time = msg.base.multi_media_time;
-    var c = new webm_Cluster(stream.cluster_time - stream.start_time, msg.data);
-
-    var mb = new ArrayBuffer(c.buffer_size());
-    c.to_buffer(mb);
-
-    push_or_queue(stream, msg, mb);
-
-    video_simple_block(stream, msg, true);
-}
-
-function process_video_stream_data(stream, msg)
-{
-    if (! stream.source_buffer)
-        return true;
-
-    if (stream.start_time == 0)
-    {
-        stream.start_time = msg.base.multi_media_time;
-        stream.video.play();
-        new_video_cluster(stream, msg);
-    }
-
-    else if (msg.base.multi_media_time - stream.cluster_time >= MAX_CLUSTER_TIME)
-        new_video_cluster(stream, msg);
-    else
-        video_simple_block(stream, msg, false);
-}
-
-function video_handle_event_debug(e)
-{
-    var s = this.spice_stream;
-    if (s.video)
-    {
-        if (STREAM_DEBUG > 0 || s.video.buffered.len > 1)
-            console.log(s.video.currentTime + ":id " +  s.id + " event " + e.type +
-                dump_media_element(s.video));
-    }
-
-    if (STREAM_DEBUG > 1 && s.media)
-        console.log("  media_source " + dump_media_source(s.media));
-
-    if (STREAM_DEBUG > 1 && s.source_buffer)
-        console.log("  source_buffer " + dump_source_buffer(s.source_buffer));
-
-    if (STREAM_DEBUG > 0 || s.queue.length > 1)
-        console.log('  queue len ' + s.queue.length + '; append_okay: ' + s.append_okay);
-}
-
-function video_debug_listen_for_one_event(name)
-{
-    this.addEventListener(name, video_handle_event_debug);
-}
-
-function listen_for_video_events(stream)
-{
-    var video_0_events = [
-        "abort", "error"
-    ];
-
-    var video_1_events = [
-        "loadstart", "suspend", "emptied", "stalled", "loadedmetadata", "loadeddata", "canplay",
-        "canplaythrough", "playing", "waiting", "seeking", "seeked", "ended", "durationchange",
-        "timeupdate", "play", "pause", "ratechange"
-    ];
-
-    var video_2_events = [
-        "progress",
-        "resize",
-        "volumechange"
-    ];
-
-    video_0_events.forEach(video_debug_listen_for_one_event, stream.video);
-    if (STREAM_DEBUG > 0)
-        video_1_events.forEach(video_debug_listen_for_one_event, stream.video);
-    if (STREAM_DEBUG > 1)
-        video_2_events.forEach(video_debug_listen_for_one_event, stream.video);
-}
diff -pruN 0.1.7-5/enums.js 0.2.2-0ubuntu3/enums.js
--- 0.1.7-5/enums.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/enums.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,368 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-
-/*----------------------------------------------------------------------------
-**  enums.js
-**      'constants' for Spice
-**--------------------------------------------------------------------------*/
-var SPICE_MAGIC         = "REDQ";
-var SPICE_VERSION_MAJOR = 2;
-var SPICE_VERSION_MINOR = 2;
-
-var SPICE_CONNECT_TIMEOUT = (30 * 1000);
-
-var SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION = 0;
-var SPICE_COMMON_CAP_AUTH_SPICE              = 1;
-var SPICE_COMMON_CAP_AUTH_SASL               = 2;
-var SPICE_COMMON_CAP_MINI_HEADER             = 3;
-
-var SPICE_TICKET_KEY_PAIR_LENGTH             = 1024;
-var SPICE_TICKET_PUBKEY_BYTES                = (SPICE_TICKET_KEY_PAIR_LENGTH / 8 + 34);
-
-var SPICE_LINK_ERR_OK                        = 0,
-    SPICE_LINK_ERR_ERROR                     = 1,
-    SPICE_LINK_ERR_INVALID_MAGIC             = 2,
-    SPICE_LINK_ERR_INVALID_DATA              = 3,
-    SPICE_LINK_ERR_VERSION_MISMATCH          = 4,
-    SPICE_LINK_ERR_NEED_SECURED              = 5,
-    SPICE_LINK_ERR_NEED_UNSECURED            = 6,
-    SPICE_LINK_ERR_PERMISSION_DENIED         = 7,
-    SPICE_LINK_ERR_BAD_CONNECTION_ID         = 8,
-    SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE     = 9;
-
-var SPICE_MSG_MIGRATE                   = 1;
-var SPICE_MSG_MIGRATE_DATA              = 2;
-var SPICE_MSG_SET_ACK                   = 3;
-var SPICE_MSG_PING                      = 4;
-var SPICE_MSG_WAIT_FOR_CHANNELS         = 5;
-var SPICE_MSG_DISCONNECTING             = 6;
-var SPICE_MSG_NOTIFY                    = 7;
-var SPICE_MSG_LIST                      = 8;
-
-var SPICE_MSG_MAIN_MIGRATE_BEGIN        = 101;
-var SPICE_MSG_MAIN_MIGRATE_CANCEL       = 102;
-var SPICE_MSG_MAIN_INIT                 = 103;
-var SPICE_MSG_MAIN_CHANNELS_LIST        = 104;
-var SPICE_MSG_MAIN_MOUSE_MODE           = 105;
-var SPICE_MSG_MAIN_MULTI_MEDIA_TIME     = 106;
-var SPICE_MSG_MAIN_AGENT_CONNECTED      = 107;
-var SPICE_MSG_MAIN_AGENT_DISCONNECTED   = 108;
-var SPICE_MSG_MAIN_AGENT_DATA           = 109;
-var SPICE_MSG_MAIN_AGENT_TOKEN          = 110;
-var SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST  = 111;
-var SPICE_MSG_MAIN_MIGRATE_END          = 112;
-var SPICE_MSG_MAIN_NAME                 = 113;
-var SPICE_MSG_MAIN_UUID                 = 114;
-var SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS = 115;
-var SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS = 116;
-var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK = 117;
-var SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK = 118;
-var SPICE_MSG_END_MAIN                  = 119;
-
-
-
-var SPICE_MSGC_ACK_SYNC                 = 1;
-var SPICE_MSGC_ACK                      = 2;
-var SPICE_MSGC_PONG                     = 3;
-var SPICE_MSGC_MIGRATE_FLUSH_MARK       = 4;
-var SPICE_MSGC_MIGRATE_DATA             = 5;
-var SPICE_MSGC_DISCONNECTING            = 6;
-
-
-var SPICE_MSGC_MAIN_CLIENT_INFO         = 101;
-var SPICE_MSGC_MAIN_MIGRATE_CONNECTED   = 102;
-var SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR = 103;
-var SPICE_MSGC_MAIN_ATTACH_CHANNELS     = 104;
-var SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST  = 105;
-var SPICE_MSGC_MAIN_AGENT_START         = 106;
-var SPICE_MSGC_MAIN_AGENT_DATA          = 107;
-var SPICE_MSGC_MAIN_AGENT_TOKEN         = 108;
-var SPICE_MSGC_MAIN_MIGRATE_END         = 109;
-var SPICE_MSGC_END_MAIN                 = 110;
-
-var SPICE_MSG_DISPLAY_MODE              = 101;
-var SPICE_MSG_DISPLAY_MARK              = 102;
-var SPICE_MSG_DISPLAY_RESET             = 103;
-var SPICE_MSG_DISPLAY_COPY_BITS         = 104;
-var SPICE_MSG_DISPLAY_INVAL_LIST        = 105;
-var SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS = 106;
-var SPICE_MSG_DISPLAY_INVAL_PALETTE     = 107;
-var SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES= 108;
-
-var SPICE_MSG_DISPLAY_STREAM_CREATE     = 122;
-var SPICE_MSG_DISPLAY_STREAM_DATA       = 123;
-var SPICE_MSG_DISPLAY_STREAM_CLIP       = 124;
-var SPICE_MSG_DISPLAY_STREAM_DESTROY    = 125;
-var SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL= 126;
-
-var SPICE_MSG_DISPLAY_DRAW_FILL         = 302;
-var SPICE_MSG_DISPLAY_DRAW_OPAQUE       = 303;
-var SPICE_MSG_DISPLAY_DRAW_COPY         = 304;
-var SPICE_MSG_DISPLAY_DRAW_BLEND        = 305;
-var SPICE_MSG_DISPLAY_DRAW_BLACKNESS    = 306;
-var SPICE_MSG_DISPLAY_DRAW_WHITENESS    = 307;
-var SPICE_MSG_DISPLAY_DRAW_INVERS       = 308;
-var SPICE_MSG_DISPLAY_DRAW_ROP3         = 309;
-var SPICE_MSG_DISPLAY_DRAW_STROKE       = 310;
-var SPICE_MSG_DISPLAY_DRAW_TEXT         = 311;
-var SPICE_MSG_DISPLAY_DRAW_TRANSPARENT  = 312;
-var SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND  = 313;
-var SPICE_MSG_DISPLAY_SURFACE_CREATE    = 314;
-var SPICE_MSG_DISPLAY_SURFACE_DESTROY   = 315;
-var SPICE_MSG_DISPLAY_STREAM_DATA_SIZED = 316;
-var SPICE_MSG_DISPLAY_MONITORS_CONFIG   = 317;
-var SPICE_MSG_DISPLAY_DRAW_COMPOSITE    = 318;
-var SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT = 319;
-
-var SPICE_MSGC_DISPLAY_INIT             = 101;
-var SPICE_MSGC_DISPLAY_STREAM_REPORT    = 102;
-
-var SPICE_MSG_INPUTS_INIT               = 101;
-var SPICE_MSG_INPUTS_KEY_MODIFIERS      = 102;
-
-var SPICE_MSG_INPUTS_MOUSE_MOTION_ACK   = 111;
-
-var SPICE_MSGC_INPUTS_KEY_DOWN          = 101;
-var SPICE_MSGC_INPUTS_KEY_UP            = 102;
-var SPICE_MSGC_INPUTS_KEY_MODIFIERS     = 103;
-
-var SPICE_MSGC_INPUTS_MOUSE_MOTION      = 111;
-var SPICE_MSGC_INPUTS_MOUSE_POSITION    = 112;
-var SPICE_MSGC_INPUTS_MOUSE_PRESS       = 113;
-var SPICE_MSGC_INPUTS_MOUSE_RELEASE     = 114;
-
-var SPICE_MSG_CURSOR_INIT               = 101;
-var SPICE_MSG_CURSOR_RESET              = 102;
-var SPICE_MSG_CURSOR_SET                = 103;
-var SPICE_MSG_CURSOR_MOVE               = 104;
-var SPICE_MSG_CURSOR_HIDE               = 105;
-var SPICE_MSG_CURSOR_TRAIL              = 106;
-var SPICE_MSG_CURSOR_INVAL_ONE          = 107;
-var SPICE_MSG_CURSOR_INVAL_ALL          = 108;
-
-var SPICE_MSG_PLAYBACK_DATA             = 101;
-var SPICE_MSG_PLAYBACK_MODE             = 102;
-var SPICE_MSG_PLAYBACK_START            = 103;
-var SPICE_MSG_PLAYBACK_STOP             = 104;
-var SPICE_MSG_PLAYBACK_VOLUME           = 105;
-var SPICE_MSG_PLAYBACK_MUTE             = 106;
-var SPICE_MSG_PLAYBACK_LATENCY          = 107;
-
-var SPICE_PLAYBACK_CAP_CELT_0_5_1       = 0;
-var SPICE_PLAYBACK_CAP_VOLUME           = 1;
-var SPICE_PLAYBACK_CAP_LATENCY          = 2;
-var SPICE_PLAYBACK_CAP_OPUS             = 3;
-
-var SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE  = 0;
-var SPICE_MAIN_CAP_NAME_AND_UUID          = 1;
-var SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS = 2;
-var SPICE_MAIN_CAP_SEAMLESS_MIGRATE       = 3;
-
-var SPICE_DISPLAY_CAP_SIZED_STREAM        = 0;
-var SPICE_DISPLAY_CAP_MONITORS_CONFIG     = 1;
-var SPICE_DISPLAY_CAP_COMPOSITE           = 2;
-var SPICE_DISPLAY_CAP_A8_SURFACE          = 3;
-var SPICE_DISPLAY_CAP_STREAM_REPORT       = 4;
-var SPICE_DISPLAY_CAP_LZ4_COMPRESSION     = 5;
-var SPICE_DISPLAY_CAP_PREF_COMPRESSION    = 6;
-var SPICE_DISPLAY_CAP_GL_SCANOUT          = 7;
-var SPICE_DISPLAY_CAP_MULTI_CODEC         = 8;
-var SPICE_DISPLAY_CAP_CODEC_MJPEG         = 9;
-var SPICE_DISPLAY_CAP_CODEC_VP8           = 10;
-
-var SPICE_AUDIO_DATA_MODE_INVALID       = 0;
-var SPICE_AUDIO_DATA_MODE_RAW           = 1;
-var SPICE_AUDIO_DATA_MODE_CELT_0_5_1    = 2;
-var SPICE_AUDIO_DATA_MODE_OPUS          = 3;
-
-var SPICE_AUDIO_FMT_INVALID             = 0;
-var SPICE_AUDIO_FMT_S16                 = 1;
-
-var SPICE_CHANNEL_MAIN                  = 1;
-var SPICE_CHANNEL_DISPLAY               = 2;
-var SPICE_CHANNEL_INPUTS                = 3;
-var SPICE_CHANNEL_CURSOR                = 4;
-var SPICE_CHANNEL_PLAYBACK              = 5;
-var SPICE_CHANNEL_RECORD                = 6;
-var SPICE_CHANNEL_TUNNEL                = 7;
-var SPICE_CHANNEL_SMARTCARD             = 8;
-var SPICE_CHANNEL_USBREDIR              = 9;
-var SPICE_CHANNEL_PORT                  = 10;
-var SPICE_CHANNEL_WEBDAV                = 11;
-
-var SPICE_SURFACE_FLAGS_PRIMARY = (1 << 0);
-
-var SPICE_NOTIFY_SEVERITY_INFO  = 0;
-var SPICE_NOTIFY_SEVERITY_WARN  = 1;
-var SPICE_NOTIFY_SEVERITY_ERROR = 2;
-
-var SPICE_MOUSE_MODE_SERVER = (1 << 0),
-    SPICE_MOUSE_MODE_CLIENT = (1 << 1),
-    SPICE_MOUSE_MODE_MASK = 0x3;
-
-var SPICE_CLIP_TYPE_NONE            = 0;
-var SPICE_CLIP_TYPE_RECTS           = 1;
-
-var SPICE_IMAGE_TYPE_BITMAP         = 0;
-var SPICE_IMAGE_TYPE_QUIC           = 1;
-var SPICE_IMAGE_TYPE_RESERVED       = 2;
-var SPICE_IMAGE_TYPE_LZ_PLT         = 100;
-var SPICE_IMAGE_TYPE_LZ_RGB         = 101;
-var SPICE_IMAGE_TYPE_GLZ_RGB        = 102;
-var SPICE_IMAGE_TYPE_FROM_CACHE     = 103;
-var SPICE_IMAGE_TYPE_SURFACE        = 104;
-var SPICE_IMAGE_TYPE_JPEG           = 105;
-var SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS = 106;
-var SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB   = 107;
-var SPICE_IMAGE_TYPE_JPEG_ALPHA     = 108;
-
-var SPICE_IMAGE_FLAGS_CACHE_ME = (1 << 0),
-    SPICE_IMAGE_FLAGS_HIGH_BITS_SET = (1 << 1),
-    SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME = (1 << 2);
-
-var SPICE_BITMAP_FLAGS_PAL_CACHE_ME = (1 << 0),
-    SPICE_BITMAP_FLAGS_PAL_FROM_CACHE = (1 << 1),
-    SPICE_BITMAP_FLAGS_TOP_DOWN = (1 << 2),
-    SPICE_BITMAP_FLAGS_MASK = 0x7;
-
-var SPICE_BITMAP_FMT_INVALID        = 0,
-    SPICE_BITMAP_FMT_1BIT_LE        = 1,
-    SPICE_BITMAP_FMT_1BIT_BE        = 2,
-    SPICE_BITMAP_FMT_4BIT_LE        = 3,
-    SPICE_BITMAP_FMT_4BIT_BE        = 4,
-    SPICE_BITMAP_FMT_8BIT           = 5,
-    SPICE_BITMAP_FMT_16BIT          = 6,
-    SPICE_BITMAP_FMT_24BIT          = 7,
-    SPICE_BITMAP_FMT_32BIT          = 8,
-    SPICE_BITMAP_FMT_RGBA           = 9;
-
-
-var SPICE_CURSOR_FLAGS_NONE = (1 << 0),
-    SPICE_CURSOR_FLAGS_CACHE_ME = (1 << 1),
-    SPICE_CURSOR_FLAGS_FROM_CACHE = (1 << 2),
-    SPICE_CURSOR_FLAGS_MASK = 0x7;
-
-var SPICE_MOUSE_BUTTON_MASK_LEFT = (1 << 0),
-    SPICE_MOUSE_BUTTON_MASK_MIDDLE = (1 << 1),
-    SPICE_MOUSE_BUTTON_MASK_RIGHT = (1 << 2),
-    SPICE_MOUSE_BUTTON_MASK_MASK = 0x7;
-    
-var SPICE_MOUSE_BUTTON_INVALID  = 0;
-var SPICE_MOUSE_BUTTON_LEFT     = 1;
-var SPICE_MOUSE_BUTTON_MIDDLE   = 2;
-var SPICE_MOUSE_BUTTON_RIGHT    = 3;
-var SPICE_MOUSE_BUTTON_UP       = 4;
-var SPICE_MOUSE_BUTTON_DOWN     = 5;
-
-var SPICE_BRUSH_TYPE_NONE = 0,
-    SPICE_BRUSH_TYPE_SOLID = 1,
-    SPICE_BRUSH_TYPE_PATTERN = 2;
-
-var SPICE_SURFACE_FMT_INVALID = 0,
-    SPICE_SURFACE_FMT_1_A = 1,
-    SPICE_SURFACE_FMT_8_A = 8,
-    SPICE_SURFACE_FMT_16_555 = 16,
-    SPICE_SURFACE_FMT_32_xRGB = 32,
-    SPICE_SURFACE_FMT_16_565 = 80,
-    SPICE_SURFACE_FMT_32_ARGB = 96;
-
-var SPICE_ROPD_INVERS_SRC = (1 << 0),
-    SPICE_ROPD_INVERS_BRUSH = (1 << 1),
-    SPICE_ROPD_INVERS_DEST = (1 << 2),
-    SPICE_ROPD_OP_PUT = (1 << 3),
-    SPICE_ROPD_OP_OR = (1 << 4),
-    SPICE_ROPD_OP_AND = (1 << 5),
-    SPICE_ROPD_OP_XOR = (1 << 6),
-    SPICE_ROPD_OP_BLACKNESS = (1 << 7),
-    SPICE_ROPD_OP_WHITENESS = (1 << 8),
-    SPICE_ROPD_OP_INVERS = (1 << 9),
-    SPICE_ROPD_INVERS_RES = (1 << 10),
-    SPICE_ROPD_MASK = 0x7ff;
-
-var LZ_IMAGE_TYPE_INVALID = 0,
-    LZ_IMAGE_TYPE_PLT1_LE = 1,
-    LZ_IMAGE_TYPE_PLT1_BE = 2,      // PLT stands for palette
-    LZ_IMAGE_TYPE_PLT4_LE = 3,
-    LZ_IMAGE_TYPE_PLT4_BE = 4,
-    LZ_IMAGE_TYPE_PLT8    = 5,
-    LZ_IMAGE_TYPE_RGB16   = 6,
-    LZ_IMAGE_TYPE_RGB24   = 7,
-    LZ_IMAGE_TYPE_RGB32   = 8,
-    LZ_IMAGE_TYPE_RGBA    = 9,
-    LZ_IMAGE_TYPE_XXXA    = 10;
-
-
-var QUIC_IMAGE_TYPE_INVALID = 0,
-    QUIC_IMAGE_TYPE_GRAY    = 1,
-    QUIC_IMAGE_TYPE_RGB16   = 2,
-    QUIC_IMAGE_TYPE_RGB24   = 3,
-    QUIC_IMAGE_TYPE_RGB32   = 4,
-    QUIC_IMAGE_TYPE_RGBA    = 5;
-
-var SPICE_INPUT_MOTION_ACK_BUNCH = 4;
-
-
-var SPICE_CURSOR_TYPE_ALPHA     = 0,
-    SPICE_CURSOR_TYPE_MONO      = 1,
-    SPICE_CURSOR_TYPE_COLOR4    = 2,
-    SPICE_CURSOR_TYPE_COLOR8    = 3,
-    SPICE_CURSOR_TYPE_COLOR16   = 4,
-    SPICE_CURSOR_TYPE_COLOR24   = 5,
-    SPICE_CURSOR_TYPE_COLOR32   = 6;
-
-var SPICE_VIDEO_CODEC_TYPE_MJPEG = 1;
-var SPICE_VIDEO_CODEC_TYPE_VP8   = 2;
-
-var VD_AGENT_PROTOCOL = 1;
-var VD_AGENT_MAX_DATA_SIZE = 2048;
-
-var VD_AGENT_MOUSE_STATE            = 1,
-    VD_AGENT_MONITORS_CONFIG        = 2,
-    VD_AGENT_REPLY                  = 3,
-    VD_AGENT_CLIPBOARD              = 4,
-    VD_AGENT_DISPLAY_CONFIG         = 5,
-    VD_AGENT_ANNOUNCE_CAPABILITIES  = 6,
-    VD_AGENT_CLIPBOARD_GRAB         = 7,
-    VD_AGENT_CLIPBOARD_REQUEST      = 8,
-    VD_AGENT_CLIPBOARD_RELEASE      = 9,
-    VD_AGENT_FILE_XFER_START        =10,
-    VD_AGENT_FILE_XFER_STATUS       =11,
-    VD_AGENT_FILE_XFER_DATA         =12,
-    VD_AGENT_CLIENT_DISCONNECTED    =13,
-    VD_AGENT_MAX_CLIPBOARD          =14;
-
-var VD_AGENT_CAP_MOUSE_STATE            = 0,
-    VD_AGENT_CAP_MONITORS_CONFIG        = 1,
-    VD_AGENT_CAP_REPLY                  = 2,
-    VD_AGENT_CAP_CLIPBOARD              = 3,
-    VD_AGENT_CAP_DISPLAY_CONFIG         = 4,
-    VD_AGENT_CAP_CLIPBOARD_BY_DEMAND    = 5,
-    VD_AGENT_CAP_CLIPBOARD_SELECTION    = 6,
-    VD_AGENT_CAP_SPARSE_MONITORS_CONFIG = 7,
-    VD_AGENT_CAP_GUEST_LINEEND_LF       = 8,
-    VD_AGENT_CAP_GUEST_LINEEND_CRLF     = 9,
-    VD_AGENT_CAP_MAX_CLIPBOARD          = 10,
-    VD_AGENT_END_CAP                    = 11;
-
-var VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA = 0,
-    VD_AGENT_FILE_XFER_STATUS_CANCELLED     = 1,
-    VD_AGENT_FILE_XFER_STATUS_ERROR         = 2,
-    VD_AGENT_FILE_XFER_STATUS_SUCCESS       = 3;
diff -pruN 0.1.7-5/filexfer.js 0.2.2-0ubuntu3/filexfer.js
--- 0.1.7-5/filexfer.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/filexfer.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,88 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2014 Red Hat, Inc.
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-function SpiceFileXferTask(id, file)
-{
-    this.id = id;
-    this.file = file;
-}
-
-SpiceFileXferTask.prototype.create_progressbar = function()
-{
-    var _this = this;
-    var cancel = document.createElement("input");
-    this.progressbar_container = document.createElement("div");
-    this.progressbar = document.createElement("progress");
-
-    cancel.type = 'button';
-    cancel.value = 'Cancel';
-    cancel.style.float = 'right';
-    cancel.onclick = function()
-    {
-        _this.cancelled = true;
-        _this.remove_progressbar();
-    };
-
-    this.progressbar.setAttribute('max', this.file.size);
-    this.progressbar.setAttribute('value', 0);
-    this.progressbar.style.width = '100%';
-    this.progressbar.style.margin = '4px auto';
-    this.progressbar.style.display = 'inline-block';
-    this.progressbar_container.style.width = '90%';
-    this.progressbar_container.style.margin = 'auto';
-    this.progressbar_container.style.padding = '4px';
-    this.progressbar_container.textContent = this.file.name;
-    this.progressbar_container.appendChild(cancel);
-    this.progressbar_container.appendChild(this.progressbar);
-    document.getElementById('spice-xfer-area').appendChild(this.progressbar_container);
-}
-
-SpiceFileXferTask.prototype.update_progressbar = function(value)
-{
-    this.progressbar.setAttribute('value', value);
-}
-
-SpiceFileXferTask.prototype.remove_progressbar = function()
-{
-    if (this.progressbar_container && this.progressbar_container.parentNode)
-        this.progressbar_container.parentNode.removeChild(this.progressbar_container);
-}
-
-function handle_file_dragover(e)
-{
-    e.stopPropagation();
-    e.preventDefault();
-    e.dataTransfer.dropEffect = 'copy';
-}
-
-function handle_file_drop(e)
-{
-    var sc = window.spice_connection;
-    var files = e.dataTransfer.files;
-
-    e.stopPropagation();
-    e.preventDefault();
-    for (var i = files.length - 1; i >= 0; i--)
-    {
-        if (files[i].type) // do not copy a directory
-            sc.file_xfer_start(files[i]);
-    }
-
-}
diff -pruN 0.1.7-5/.gitignore 0.2.2-0ubuntu3/.gitignore
--- 0.1.7-5/.gitignore	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/.gitignore	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,2 @@
+spice-html5.spec
+package.json
diff -pruN 0.1.7-5/inputs.js 0.2.2-0ubuntu3/inputs.js
--- 0.1.7-5/inputs.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/inputs.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,280 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
- ** Modifier Keystates
- **     These need to be tracked because focus in and out can get the keyboard
- **     out of sync.
- **------------------------------------------------------------------------*/
-var Shift_state = -1;
-var Ctrl_state = -1;
-var Alt_state = -1;
-var Meta_state = -1;
-
-/*----------------------------------------------------------------------------
-**  SpiceInputsConn
-**      Drive the Spice Inputs channel (e.g. mouse + keyboard)
-**--------------------------------------------------------------------------*/
-function SpiceInputsConn()
-{
-    SpiceConn.apply(this, arguments);
-
-    this.mousex = undefined;
-    this.mousey = undefined;
-    this.button_state = 0;
-    this.waiting_for_ack = 0;
-}
-
-SpiceInputsConn.prototype = Object.create(SpiceConn.prototype);
-SpiceInputsConn.prototype.process_channel_message = function(msg)
-{
-    if (msg.type == SPICE_MSG_INPUTS_INIT)
-    {
-        var inputs_init = new SpiceMsgInputsInit(msg.data);
-        this.keyboard_modifiers = inputs_init.keyboard_modifiers;
-        DEBUG > 1 && console.log("MsgInputsInit - modifier " + this.keyboard_modifiers);
-        // FIXME - We don't do anything with the keyboard modifiers...
-        return true;
-    }
-    if (msg.type == SPICE_MSG_INPUTS_KEY_MODIFIERS)
-    {
-        var key = new SpiceMsgInputsKeyModifiers(msg.data);
-        this.keyboard_modifiers = key.keyboard_modifiers;
-        DEBUG > 1 && console.log("MsgInputsKeyModifiers - modifier " + this.keyboard_modifiers);
-        // FIXME - We don't do anything with the keyboard modifiers...
-        return true;
-    }
-    if (msg.type == SPICE_MSG_INPUTS_MOUSE_MOTION_ACK)
-    {
-        DEBUG > 1 && console.log("mouse motion ack");
-        this.waiting_for_ack -= SPICE_INPUT_MOTION_ACK_BUNCH;
-        return true;
-    }
-    return false;
-}
-
-
-
-function handle_mousemove(e)
-{
-    var msg = new SpiceMiniData();
-    var move;
-    if (this.sc.mouse_mode == SPICE_MOUSE_MODE_CLIENT)
-    {
-        move = new SpiceMsgcMousePosition(this.sc, e)
-        msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_POSITION, move);
-    }
-    else
-    {
-        move = new SpiceMsgcMouseMotion(this.sc, e)
-        msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_MOTION, move);
-    }
-    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
-    {
-        if (this.sc.inputs.waiting_for_ack < (2 * SPICE_INPUT_MOTION_ACK_BUNCH))
-        {
-            this.sc.inputs.send_msg(msg);
-            this.sc.inputs.waiting_for_ack++;
-        }
-        else
-        {
-            DEBUG > 0 && this.sc.log_info("Discarding mouse motion");
-        }
-    }
-
-    if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor)
-    {
-        this.sc.cursor.spice_simulated_cursor.style.display = 'block';
-        this.sc.cursor.spice_simulated_cursor.style.left = e.pageX - this.sc.cursor.spice_simulated_cursor.spice_hot_x + 'px';
-        this.sc.cursor.spice_simulated_cursor.style.top = e.pageY - this.sc.cursor.spice_simulated_cursor.spice_hot_y + 'px';
-        e.preventDefault();
-    }
-
-}
-
-function handle_mousedown(e)
-{
-    var press = new SpiceMsgcMousePress(this.sc, e)
-    var msg = new SpiceMiniData();
-    msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press);
-    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
-        this.sc.inputs.send_msg(msg);
-
-    e.preventDefault();
-}
-
-function handle_contextmenu(e)
-{
-    e.preventDefault();
-    return false;
-}
-
-function handle_mouseup(e)
-{
-    var release = new SpiceMsgcMouseRelease(this.sc, e)
-    var msg = new SpiceMiniData();
-    msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release);
-    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
-        this.sc.inputs.send_msg(msg);
-
-    e.preventDefault();
-}
-
-function handle_mousewheel(e)
-{
-    var press = new SpiceMsgcMousePress;
-    var release = new SpiceMsgcMouseRelease;
-    if (e.deltaY < 0)
-        press.button = release.button = SPICE_MOUSE_BUTTON_UP;
-    else
-        press.button = release.button = SPICE_MOUSE_BUTTON_DOWN;
-    press.buttons_state = 0;
-    release.buttons_state = 0;
-
-    var msg = new SpiceMiniData();
-    msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_PRESS, press);
-    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
-        this.sc.inputs.send_msg(msg);
-
-    msg.build_msg(SPICE_MSGC_INPUTS_MOUSE_RELEASE, release);
-    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
-        this.sc.inputs.send_msg(msg);
-
-    e.preventDefault();
-}
-
-function handle_keydown(e)
-{
-    var key = new SpiceMsgcKeyDown(e)
-    var msg = new SpiceMiniData();
-    check_and_update_modifiers(e, key.code, this.sc);
-    msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key);
-    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
-        this.sc.inputs.send_msg(msg);
-
-    e.preventDefault();
-}
-
-function handle_keyup(e)
-{
-    var key = new SpiceMsgcKeyUp(e)
-    var msg = new SpiceMiniData();
-    check_and_update_modifiers(e, key.code, this.sc);
-    msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key);
-    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
-        this.sc.inputs.send_msg(msg);
-
-    e.preventDefault();
-}
-
-function sendCtrlAltDel()
-{
-    if (sc && sc.inputs && sc.inputs.state === "ready"){
-        var key = new SpiceMsgcKeyDown();
-        var msg = new SpiceMiniData();
-
-        update_modifier(true, KEY_LCtrl, sc);
-        update_modifier(true, KEY_Alt, sc);
-
-        key.code = KEY_KP_Decimal;
-        msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key);
-        sc.inputs.send_msg(msg);
-        msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key);
-        sc.inputs.send_msg(msg);
-
-        if(Ctrl_state == false) update_modifier(false, KEY_LCtrl, sc);
-        if(Alt_state == false) update_modifier(false, KEY_Alt, sc);
-    }
-}
-
-function update_modifier(state, code, sc)
-{
-    var msg = new SpiceMiniData();
-    if (!state)
-    {
-        var key = new SpiceMsgcKeyUp()
-        key.code =(0x80|code);
-        msg.build_msg(SPICE_MSGC_INPUTS_KEY_UP, key);
-    }
-    else
-    {
-        var key = new SpiceMsgcKeyDown()
-        key.code = code;
-        msg.build_msg(SPICE_MSGC_INPUTS_KEY_DOWN, key);
-    }
-
-    sc.inputs.send_msg(msg);
-}
-
-function check_and_update_modifiers(e, code, sc)
-{
-    if (Shift_state === -1)
-    {
-        Shift_state = e.shiftKey;
-        Ctrl_state = e.ctrlKey;
-        Alt_state = e.altKey;
-        Meta_state = e.metaKey;
-    }
-
-    if (code === KEY_ShiftL)
-        Shift_state = true;
-    else if (code === KEY_Alt)
-        Alt_state = true;
-    else if (code === KEY_LCtrl)
-        Ctrl_state = true;
-    else if (code === 0xE0B5)
-        Meta_state = true;
-    else if (code === (0x80|KEY_ShiftL))
-        Shift_state = false;
-    else if (code === (0x80|KEY_Alt))
-        Alt_state = false;
-    else if (code === (0x80|KEY_LCtrl))
-        Ctrl_state = false;
-    else if (code === (0x80|0xE0B5))
-        Meta_state = false;
-
-    if (sc && sc.inputs && sc.inputs.state === "ready")
-    {
-        if (Shift_state != e.shiftKey)
-        {
-            console.log("Shift state out of sync");
-            update_modifier(e.shiftKey, KEY_ShiftL, sc);
-            Shift_state = e.shiftKey;
-        }
-        if (Alt_state != e.altKey)
-        {
-            console.log("Alt state out of sync");
-            update_modifier(e.altKey, KEY_Alt, sc);
-            Alt_state = e.altKey;
-        }
-        if (Ctrl_state != e.ctrlKey)
-        {
-            console.log("Ctrl state out of sync");
-            update_modifier(e.ctrlKey, KEY_LCtrl, sc);
-            Ctrl_state = e.ctrlKey;
-        }
-        if (Meta_state != e.metaKey)
-        {
-            console.log("Meta state out of sync");
-            update_modifier(e.metaKey, 0xE0B5, sc);
-            Meta_state = e.metaKey;
-        }
-    }
-}
diff -pruN 0.1.7-5/lz.js 0.2.2-0ubuntu3/lz.js
--- 0.1.7-5/lz.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/lz.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,166 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-
-/*----------------------------------------------------------------------------
-**  lz.js
-**      Functions for handling SPICE_IMAGE_TYPE_LZ_RGB
-**  Adapted from lz.c .
-**--------------------------------------------------------------------------*/
-function lz_rgb32_decompress(in_buf, at, out_buf, type, default_alpha)
-{
-    var encoder = at;
-    var op = 0;
-    var ctrl;
-    var ctr = 0;
-
-    for (ctrl = in_buf[encoder++]; (op * 4) < out_buf.length; ctrl = in_buf[encoder++])
-    {
-        var ref = op;
-        var len = ctrl >> 5;
-        var ofs = (ctrl & 31) << 8;
-
-//if (type == LZ_IMAGE_TYPE_RGBA)
-//console.log(ctr++ + ": from " + (encoder + 28) + ", ctrl " + ctrl + ", len " + len + ", ofs " + ofs + ", op " + op);
-        if (ctrl >= 32) {
-
-            var code;
-            len--;
-
-            if (len == 7 - 1) {
-                do {
-                    code = in_buf[encoder++];
-                    len += code;
-                } while (code == 255);
-            }
-            code = in_buf[encoder++];
-            ofs += code;
-
-
-            if (code == 255) {
-                if ((ofs - code) == (31 << 8)) {
-                    ofs = in_buf[encoder++] << 8;
-                    ofs += in_buf[encoder++];
-                    ofs += 8191;
-                }
-            }
-            len += 1;
-            if (type == LZ_IMAGE_TYPE_RGBA)
-                len += 2;
-
-            ofs += 1;
-
-            ref -= ofs;
-            if (ref == (op - 1)) {
-                var b = ref;
-//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha " + out_buf[(b*4)+3] + " dupped into pixel " + op + " through pixel " + (op + len));
-                for (; len; --len) {
-                    if (type == LZ_IMAGE_TYPE_RGBA)
-                    {
-                        out_buf[(op*4) + 3] = out_buf[(b*4)+3];
-                    }
-                    else
-                    {
-                        for (i = 0; i < 4; i++)
-                            out_buf[(op*4) + i] = out_buf[(b*4)+i];
-                    }
-                    op++;
-                }
-            } else {
-//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha copied to pixel " + op + " through " + (op + len) + " from " + ref);
-                for (; len; --len) {
-                    if (type == LZ_IMAGE_TYPE_RGBA)
-                    {
-                        out_buf[(op*4) + 3] = out_buf[(ref*4)+3];
-                    }
-                    else
-                    {
-                        for (i = 0; i < 4; i++)
-                            out_buf[(op*4) + i] = out_buf[(ref*4)+i];
-                    }
-                    op++; ref++;
-                }
-            }
-        } else {
-            ctrl++;
-
-            if (type == LZ_IMAGE_TYPE_RGBA)
-            {
-//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
-                out_buf[(op*4) + 3] = in_buf[encoder++];
-            }
-            else
-            {
-                out_buf[(op*4) + 0] = in_buf[encoder + 2];
-                out_buf[(op*4) + 1] = in_buf[encoder + 1];
-                out_buf[(op*4) + 2] = in_buf[encoder + 0];
-                if (default_alpha)
-                    out_buf[(op*4) + 3] = 255;
-                encoder += 3;
-            }
-            op++;
-
-
-            for (--ctrl; ctrl; ctrl--) {
-                if (type == LZ_IMAGE_TYPE_RGBA)
-                {
-//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
-                    out_buf[(op*4) + 3] = in_buf[encoder++];
-                }
-                else
-                {
-                    out_buf[(op*4) + 0] = in_buf[encoder + 2];
-                    out_buf[(op*4) + 1] = in_buf[encoder + 1];
-                    out_buf[(op*4) + 2] = in_buf[encoder + 0];
-                    if (default_alpha)
-                        out_buf[(op*4) + 3] = 255;
-                    encoder += 3;
-                }
-                op++;
-            }
-        }
-
-    }
-    return encoder - 1;
-}
-
-function convert_spice_lz_to_web(context, lz_image)
-{
-    var at;
-    if (lz_image.type === LZ_IMAGE_TYPE_RGB32 || lz_image.type === LZ_IMAGE_TYPE_RGBA)
-    {
-        var u8 = new Uint8Array(lz_image.data);
-        var ret = context.createImageData(lz_image.width, lz_image.height);
-
-        at = lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGB32, lz_image.type != LZ_IMAGE_TYPE_RGBA);
-        if (lz_image.type == LZ_IMAGE_TYPE_RGBA)
-            lz_rgb32_decompress(u8, at, ret.data, LZ_IMAGE_TYPE_RGBA, false);
-    }
-    else if (lz_image.type === LZ_IMAGE_TYPE_XXXA)
-    {
-        var u8 = new Uint8Array(lz_image.data);
-        var ret = context.createImageData(lz_image.width, lz_image.height);
-        lz_rgb32_decompress(u8, 0, ret.data, LZ_IMAGE_TYPE_RGBA, false);
-    }
-    else
-        return undefined;
-
-    return ret;
-}
diff -pruN 0.1.7-5/main.js 0.2.2-0ubuntu3/main.js
--- 0.1.7-5/main.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/main.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,486 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  SpiceMainConn
-**      This is the master Javascript class for establishing and
-**  managing a connection to a Spice Server.
-**  
-**      Invocation:  You must pass an object with properties as follows:
-**          uri         (required)  Uri of a WebSocket listener that is
-**                                  connected to a spice server.
-**          password    (required)  Password to send to the spice server
-**          message_id  (optional)  Identifier of an element in the DOM
-**                                  where SpiceConn will write messages.
-**                                  It will use classes spice-messages-x,
-**                                  where x is one of info, warning, or error.
-**          screen_id   (optional)  Identifier of an element in the DOM
-**                                  where SpiceConn will create any new
-**                                  client screens.  This is the main UI.
-**          dump_id     (optional)  If given, an element to use for
-**                                  dumping every single image + canvas drawn.
-**                                  Sometimes useful for debugging.
-**          onerror     (optional)  If given, a function to receive async
-**                                  errors.  Note that you should also catch
-**                                  errors for ones that occur inline
-**          onagent     (optional)  If given, a function to be called when
-**                                  a VD agent is connected; a good opportunity
-**                                  to request a resize
-**
-**  Throws error if there are troubles.  Requires a modern (by 2012 standards)
-**      browser, including WebSocket and WebSocket.binaryType == arraybuffer
-**
-**--------------------------------------------------------------------------*/
-function SpiceMainConn()
-{
-    if (typeof WebSocket === "undefined")
-        throw new Error("WebSocket unavailable.  You need to use a different browser.");
-
-    SpiceConn.apply(this, arguments);
-
-    this.agent_msg_queue = [];
-    this.file_xfer_tasks = {};
-    this.file_xfer_task_id = 0;
-    this.file_xfer_read_queue = [];
-}
-
-SpiceMainConn.prototype = Object.create(SpiceConn.prototype);
-SpiceMainConn.prototype.process_channel_message = function(msg)
-{
-    if (msg.type == SPICE_MSG_MAIN_MIGRATE_BEGIN)
-    {
-        this.known_unimplemented(msg.type, "Main Migrate Begin");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MIGRATE_CANCEL)
-    {
-        this.known_unimplemented(msg.type, "Main Migrate Cancel");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_INIT)
-    {
-        this.log_info("Connected to " + this.ws.url);
-        this.report_success("Connected")
-        this.main_init = new SpiceMsgMainInit(msg.data);
-        this.connection_id = this.main_init.session_id;
-        this.agent_tokens = this.main_init.agent_tokens;
-
-        if (DEBUG > 0)
-        {
-            // FIXME - there is a lot here we don't handle; mouse modes, agent,
-            //          ram_hint, multi_media_time
-            this.log_info("session id "                 + this.main_init.session_id +
-                          " ; display_channels_hint "   + this.main_init.display_channels_hint +
-                          " ; supported_mouse_modes "   + this.main_init.supported_mouse_modes +
-                          " ; current_mouse_mode "      + this.main_init.current_mouse_mode +
-                          " ; agent_connected "         + this.main_init.agent_connected +
-                          " ; agent_tokens "            + this.main_init.agent_tokens +
-                          " ; multi_media_time "        + this.main_init.multi_media_time +
-                          " ; ram_hint "                + this.main_init.ram_hint);
-        }
-
-        this.our_mm_time = Date.now();
-        this.mm_time = this.main_init.multi_media_time;
-
-        this.handle_mouse_mode(this.main_init.current_mouse_mode,
-                               this.main_init.supported_mouse_modes);
-
-        if (this.main_init.agent_connected)
-            this.connect_agent();
-
-        var attach = new SpiceMiniData;
-        attach.type = SPICE_MSGC_MAIN_ATTACH_CHANNELS;
-        attach.size = attach.buffer_size();
-        this.send_msg(attach);
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MOUSE_MODE)
-    {
-        var mode = new SpiceMsgMainMouseMode(msg.data);
-        DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode);
-        this.handle_mouse_mode(mode.current_mode, mode.supported_modes);
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MULTI_MEDIA_TIME)
-    {
-        this.known_unimplemented(msg.type, "Main Multi Media Time");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_CHANNELS_LIST)
-    {
-        var i;
-        var chans;
-        DEBUG > 0 && console.log("channels");
-        chans = new SpiceMsgChannels(msg.data);
-        for (i = 0; i < chans.channels.length; i++)
-        {
-            var conn = {
-                        uri: this.ws.url,
-                        parent: this,
-                        connection_id : this.connection_id,
-                        type : chans.channels[i].type,
-                        chan_id : chans.channels[i].id
-                    };
-            if (chans.channels[i].type == SPICE_CHANNEL_DISPLAY)
-                this.display = new SpiceDisplayConn(conn);
-            else if (chans.channels[i].type == SPICE_CHANNEL_INPUTS)
-            {
-                this.inputs = new SpiceInputsConn(conn);
-                this.inputs.mouse_mode = this.mouse_mode;
-            }
-            else if (chans.channels[i].type == SPICE_CHANNEL_CURSOR)
-                this.cursor = new SpiceCursorConn(conn);
-            else if (chans.channels[i].type == SPICE_CHANNEL_PLAYBACK)
-                this.cursor = new SpicePlaybackConn(conn);
-            else
-            {
-                if (! ("extra_channels" in this))
-                    this.extra_channels = [];
-                this.extra_channels[i] = new SpiceConn(conn);
-                this.log_err("Channel type " + this.extra_channels[i].channel_type() + " not implemented");
-            }
-
-        }
-
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED)
-    {
-        this.connect_agent();
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS)
-    {
-        var connected_tokens = new SpiceMsgMainAgentTokens(msg.data);
-        this.agent_tokens = connected_tokens.num_tokens;
-        this.connect_agent();
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_AGENT_TOKEN)
-    {
-        var remaining_tokens, tokens = new SpiceMsgMainAgentTokens(msg.data);
-        this.agent_tokens += tokens.num_tokens;
-        this.send_agent_message_queue();
-
-        remaining_tokens = this.agent_tokens;
-        while (remaining_tokens > 0 && this.file_xfer_read_queue.length > 0)
-        {
-            var xfer_task = this.file_xfer_read_queue.shift();
-            this.file_xfer_read(xfer_task, xfer_task.read_bytes);
-            remaining_tokens--;
-        }
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_AGENT_DISCONNECTED)
-    {
-        this.agent_connected = false;
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_AGENT_DATA)
-    {
-        var agent_data = new SpiceMsgMainAgentData(msg.data);
-        if (agent_data.type == VD_AGENT_ANNOUNCE_CAPABILITIES)
-        {
-            var agent_caps = new VDAgentAnnounceCapabilities(agent_data.data);
-            if (agent_caps.request)
-                this.announce_agent_capabilities(0);
-            return true;
-        }
-        else if (agent_data.type == VD_AGENT_FILE_XFER_STATUS)
-        {
-            this.handle_file_xfer_status(new VDAgentFileXferStatusMessage(agent_data.data));
-            return true;
-        }
-
-        return false;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST)
-    {
-        this.known_unimplemented(msg.type, "Main Migrate Switch Host");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MIGRATE_END)
-    {
-        this.known_unimplemented(msg.type, "Main Migrate End");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_NAME)
-    {
-        this.known_unimplemented(msg.type, "Main Name");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_UUID)
-    {
-        this.known_unimplemented(msg.type, "Main UUID");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS)
-    {
-        this.known_unimplemented(msg.type, "Main Migrate Begin Seamless");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK)
-    {
-        this.known_unimplemented(msg.type, "Main Migrate Dst Seamless ACK");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK)
-    {
-        this.known_unimplemented(msg.type, "Main Migrate Dst Seamless NACK");
-        return true;
-    }
-
-    return false;
-}
-
-SpiceMainConn.prototype.stop = function(msg)
-{
-    this.state = "closing";
-
-    if (this.inputs)
-    {
-        this.inputs.cleanup();
-        this.inputs = undefined;
-    }
-
-    if (this.cursor)
-    {
-        this.cursor.cleanup();
-        this.cursor = undefined;
-    }
-
-    if (this.display)
-    {
-        this.display.cleanup();
-        this.display.destroy_surfaces();
-        this.display = undefined;
-    }
-
-    this.cleanup();
-
-    if ("extra_channels" in this)
-        for (var e in this.extra_channels)
-            this.extra_channels[e].cleanup();
-    this.extra_channels = undefined;
-}
-
-SpiceMainConn.prototype.send_agent_message_queue = function(message)
-{
-    if (!this.agent_connected)
-        return;
-
-    if (message)
-        this.agent_msg_queue.push(message);
-
-    while (this.agent_tokens > 0 && this.agent_msg_queue.length > 0)
-    {
-        var mr = this.agent_msg_queue.shift();
-        this.send_msg(mr);
-        this.agent_tokens--;
-    }
-}
-
-SpiceMainConn.prototype.send_agent_message = function(type, message)
-{
-    var agent_data = new SpiceMsgcMainAgentData(type, message);
-    var sb = 0, maxsize = VD_AGENT_MAX_DATA_SIZE - SpiceMiniData.prototype.buffer_size();
-    var data = new ArrayBuffer(agent_data.buffer_size());
-    agent_data.to_buffer(data);
-    while (sb < agent_data.buffer_size())
-    {
-        var eb = Math.min(sb + maxsize, agent_data.buffer_size());
-        var mr = new SpiceMiniData();
-        mr.type = SPICE_MSGC_MAIN_AGENT_DATA;
-        mr.size = eb - sb;
-        mr.data = data.slice(sb, eb);
-        this.send_agent_message_queue(mr);
-        sb = eb;
-    }
-}
-
-SpiceMainConn.prototype.announce_agent_capabilities = function(request)
-{
-    var caps = new VDAgentAnnounceCapabilities(request, (1 << VD_AGENT_CAP_MOUSE_STATE) |
-                                                        (1 << VD_AGENT_CAP_MONITORS_CONFIG) |
-                                                        (1 << VD_AGENT_CAP_REPLY));
-    this.send_agent_message(VD_AGENT_ANNOUNCE_CAPABILITIES, caps);
-}
-
-SpiceMainConn.prototype.resize_window = function(flags, width, height, depth, x, y)
-{
-    var monitors_config = new VDAgentMonitorsConfig(flags, width, height, depth, x, y);
-    this.send_agent_message(VD_AGENT_MONITORS_CONFIG, monitors_config);
-}
-
-SpiceMainConn.prototype.file_xfer_start = function(file)
-{
-    var task_id, xfer_start, task;
-
-    task_id = this.file_xfer_task_id++;
-    task = new SpiceFileXferTask(task_id, file);
-    task.create_progressbar();
-    this.file_xfer_tasks[task_id] = task;
-    xfer_start = new VDAgentFileXferStartMessage(task_id, file.name, file.size);
-    this.send_agent_message(VD_AGENT_FILE_XFER_START, xfer_start);
-}
-
-SpiceMainConn.prototype.handle_file_xfer_status = function(file_xfer_status)
-{
-    var xfer_error, xfer_task;
-    if (!this.file_xfer_tasks[file_xfer_status.id])
-    {
-        return;
-    }
-    xfer_task = this.file_xfer_tasks[file_xfer_status.id];
-    switch (file_xfer_status.result)
-    {
-        case VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA:
-            this.file_xfer_read(xfer_task);
-            return;
-        case VD_AGENT_FILE_XFER_STATUS_CANCELLED:
-            xfer_error = "transfer is cancelled by spice agent";
-            break;
-        case VD_AGENT_FILE_XFER_STATUS_ERROR:
-            xfer_error = "some errors occurred in the spice agent";
-            break;
-        case VD_AGENT_FILE_XFER_STATUS_SUCCESS:
-            break;
-        default:
-            xfer_error = "unhandled status type: " + file_xfer_status.result;
-            break;
-    }
-
-    this.file_xfer_completed(xfer_task, xfer_error)
-}
-
-SpiceMainConn.prototype.file_xfer_read = function(file_xfer_task, start_byte)
-{
-    var FILE_XFER_CHUNK_SIZE = 32 * VD_AGENT_MAX_DATA_SIZE;
-    var _this = this;
-    var sb, eb;
-    var slice, reader;
-
-    if (!file_xfer_task ||
-        !this.file_xfer_tasks[file_xfer_task.id] ||
-        (start_byte > 0 && start_byte == file_xfer_task.file.size))
-    {
-        return;
-    }
-
-    if (file_xfer_task.cancelled)
-    {
-        var xfer_status = new VDAgentFileXferStatusMessage(file_xfer_task.id,
-                                                           VD_AGENT_FILE_XFER_STATUS_CANCELLED);
-        this.send_agent_message(VD_AGENT_FILE_XFER_STATUS, xfer_status);
-        delete this.file_xfer_tasks[file_xfer_task.id];
-        return;
-    }
-
-    sb = start_byte || 0,
-    eb = Math.min(sb + FILE_XFER_CHUNK_SIZE, file_xfer_task.file.size);
-
-    if (!this.agent_tokens)
-    {
-        file_xfer_task.read_bytes = sb;
-        this.file_xfer_read_queue.push(file_xfer_task);
-        return;
-    }
-
-    reader = new FileReader();
-    reader.onload = function(e)
-    {
-        var xfer_data = new VDAgentFileXferDataMessage(file_xfer_task.id,
-                                                       e.target.result.byteLength,
-                                                       e.target.result);
-        _this.send_agent_message(VD_AGENT_FILE_XFER_DATA, xfer_data);
-        _this.file_xfer_read(file_xfer_task, eb);
-        file_xfer_task.update_progressbar(eb);
-    };
-
-    slice = file_xfer_task.file.slice(sb, eb);
-    reader.readAsArrayBuffer(slice);
-}
-
-SpiceMainConn.prototype.file_xfer_completed = function(file_xfer_task, error)
-{
-    if (error)
-        this.log_err(error);
-    else
-        this.log_info("transfer of '" + file_xfer_task.file.name +"' was successful");
-
-    file_xfer_task.remove_progressbar();
-
-    delete this.file_xfer_tasks[file_xfer_task.id];
-}
-
-SpiceMainConn.prototype.connect_agent = function()
-{
-    this.agent_connected = true;
-
-    var agent_start = new SpiceMsgcMainAgentStart(~0);
-    var mr = new SpiceMiniData();
-    mr.build_msg(SPICE_MSGC_MAIN_AGENT_START, agent_start);
-    this.send_msg(mr);
-
-    this.announce_agent_capabilities(1);
-
-    if (this.onagent !== undefined)
-        this.onagent(this);
-
-}
-
-SpiceMainConn.prototype.handle_mouse_mode = function(current, supported)
-{
-    this.mouse_mode = current;
-    if (current != SPICE_MOUSE_MODE_CLIENT && (supported & SPICE_MOUSE_MODE_CLIENT))
-    {
-        var mode_request = new SpiceMsgcMainMouseModeRequest(SPICE_MOUSE_MODE_CLIENT);
-        var mr = new SpiceMiniData();
-        mr.build_msg(SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request);
-        this.send_msg(mr);
-    }
-
-    if (this.inputs)
-        this.inputs.mouse_mode = current;
-}
-
-/* Shift current time to attempt to get a time matching that of the server */
-SpiceMainConn.prototype.relative_now = function()
-{
-    var ret = (Date.now() - this.our_mm_time) + this.mm_time;
-    return ret;
-}
diff -pruN 0.1.7-5/Makefile 0.2.2-0ubuntu3/Makefile
--- 0.1.7-5/Makefile	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/Makefile	2019-08-06 11:45:18.000000000 +0000
@@ -26,23 +26,35 @@ endif
 
 source_for_rpm = $(HOME)/rpmbuild/SOURCES/spice-html5-$(version).tar.gz
 
-.PHONY: usage spice-html5.spec rpm tar gittar local git install
+.PHONY: usage spice-html5.spec package.json rpm tar gittar local git install
 
 usage:
 	@echo "This project does not normally need to be built.  See the README."
 	@echo " "
-	@echo "This Makefile is mostly used for creating RPM packages, which you"
-	@echo "can do by invoking 'make local' to use the current working directory,"
-	@echo "or 'make git' to use the latest git HEAD."
-	@echo "You can specify an alternate source tarball like this:"
-	@echo "  make source=/my/alternate/source local"
-	@echo "You can specifcy a specific git tag like this:"
-	@echo "  make tag=my_specific_tag git"
-	@echo "Results generally go in ~/rpmbuild"
+	@echo "This Makefile is used for creating RPM packages and the package.json file used by npm."
+	@echo " "
+	@echo "Building an rpm: "
+	@echo "  Invoke 'make local' to make an rpm with the current working directory,"
+	@echo "  or 'make git' to make an rpm with the latest git HEAD."
+	@echo "  You can specify an alternate source tarball like this:"
+	@echo "    make source=/my/alternate/source local"
+	@echo "  You can specify a specific git tag like this:"
+	@echo "    make tag=my_specific_tag git"
+	@echo "  Results generally go in ~/rpmbuild"
+	@echo " "
+	@echo "Preparing for an npm publish:"
+	@echo "    make package.json"
+	@echo "  where you can specify"
+	@echo "    make tag=my_specific_tag package.json"
+	@echo "  to prepare a particular release."
+
 
 spice-html5.spec:
 	sed -e "s/VERSION/$(version)/" < spice-html5.spec.in > spice-html5.spec
 
+package.json:
+	sed -e "s/VERSION/$(version)/" < package.json.in > package.json
+
 tar:
 	if [ "$(source)x" = "x" ] ; then \
 	    tar -czf $(source_for_rpm) --exclude=.git --transform='s!^!spice-html5-$(version)/!' * ; \
diff -pruN 0.1.7-5/package.json.in 0.2.2-0ubuntu3/package.json.in
--- 0.1.7-5/package.json.in	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/package.json.in	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,21 @@
+{
+  "name": "spice-html5",
+  "version": "VERSION",
+  "description": "Spice Javascript client",
+  "main": "src/main.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://gitlab.freedesktop.org/spice/spice-html5.git"
+  },
+  "keywords": [
+    "spice",
+    "html5",
+    "websockify"
+  ],
+  "homepage": "https://www.spice-space.org",
+  "author": "SPICE Project <spice-devel@lists.freedesktop.org> (https://www.spice-space.org)",
+  "license": "LGPL-3.0-or-later"
+}
diff -pruN 0.1.7-5/playback.js 0.2.2-0ubuntu3/playback.js
--- 0.1.7-5/playback.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/playback.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,360 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  SpicePlaybackConn
-**      Drive the Spice Playback channel (sound out)
-**--------------------------------------------------------------------------*/
-function SpicePlaybackConn()
-{
-    SpiceConn.apply(this, arguments);
-
-    this.queue = new Array();
-    this.append_okay = false;
-    this.start_time = 0;
-    this.skip_until = 0;
-    this.gap_time = 0;
-}
-
-SpicePlaybackConn.prototype = Object.create(SpiceConn.prototype);
-SpicePlaybackConn.prototype.process_channel_message = function(msg)
-{
-    if (!!!window.MediaSource)
-    {
-        this.log_err('MediaSource API is not available');
-        return false;
-    }
-
-    if (msg.type == SPICE_MSG_PLAYBACK_START)
-    {
-        var start = new SpiceMsgPlaybackStart(msg.data);
-
-        PLAYBACK_DEBUG > 0 && console.log("PlaybackStart; frequency " + start.frequency);
-
-        if (start.frequency != OPUS_FREQUENCY)
-        {
-            this.log_err('This player cannot handle frequency ' + start.frequency);
-            return false;
-        }
-
-        if (start.channels != OPUS_CHANNELS)
-        {
-            this.log_err('This player cannot handle ' + start.channels + ' channels');
-            return false;
-        }
-
-        if (start.format != SPICE_AUDIO_FMT_S16)
-        {
-            this.log_err('This player cannot format ' + start.format);
-            return false;
-        }
-
-        if (! this.source_buffer)
-        {
-            this.media_source = new MediaSource();
-            this.media_source.spiceconn = this;
-
-            this.audio = document.createElement("audio");
-            this.audio.spiceconn = this;
-            this.audio.setAttribute('autoplay', true);
-            this.audio.src = window.URL.createObjectURL(this.media_source);
-            document.getElementById(this.parent.screen_id).appendChild(this.audio);
-
-            this.media_source.addEventListener('sourceopen', handle_source_open, false);
-            this.media_source.addEventListener('sourceended', handle_source_ended, false);
-            this.media_source.addEventListener('sourceclosed', handle_source_closed, false);
-
-            this.bytes_written = 0;
-
-            return true;
-        }
-    }
-
-    if (msg.type == SPICE_MSG_PLAYBACK_DATA)
-    {
-        var data = new SpiceMsgPlaybackData(msg.data);
-
-        // If this packet has the same time as the last, just bump up by one.
-        if (this.last_data_time && data.time <= this.last_data_time)
-        {
-            // FIXME - this is arguably wrong.  But delaying the transmission was worse,
-            //          in initial testing.  Could use more research.
-            PLAYBACK_DEBUG > 1 && console.log("Hacking time of " + data.time + " to " + this.last_data_time + 1);
-            data.time = this.last_data_time + 1;
-        }
-
-        if (! this.source_buffer)
-            return true;
-
-        /* Gap detection:  If there has been a delay since our last packet, then audio must
-             have paused.  Handling that gets tricky.  In Chrome, you can seek forward,
-             but you cannot in Firefox.  And seeking forward in Chrome is nice, as it keeps
-             Chrome from being overly cautious in it's buffer strategy.
-
-             So we do two things.  First, we seek forward.  Second, we compute how much of a gap
-             there would have been, and essentially eliminate it.
-        */
-        if (this.last_data_time && data.time >= (this.last_data_time + GAP_DETECTION_THRESHOLD))
-        {
-            this.skip_until = data.time;
-            this.gap_time = (data.time - this.start_time) - 
-              (this.source_buffer.buffered.end(this.source_buffer.buffered.end.length - 1) * 1000.0).toFixed(0);
-        }
-
-        this.last_data_time = data.time;
-
-
-        PLAYBACK_DEBUG > 1 && console.log("PlaybackData; time " + data.time + "; length " + data.data.byteLength);
-
-        if (this.start_time == 0)
-            this.start_playback(data);
-
-        else if (data.time - this.cluster_time >= MAX_CLUSTER_TIME || this.skip_until > 0)
-            this.new_cluster(data);
-
-        else
-            this.simple_block(data, false);
-
-        if (this.skip_until > 0)
-        {
-            this.audio.currentTime = (this.skip_until - this.start_time - this.gap_time) / 1000.0;
-            this.skip_until = 0;
-        }
-
-        if (this.audio.paused)
-            this.audio.play();
-
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_PLAYBACK_MODE)
-    {
-        var mode = new SpiceMsgPlaybackMode(msg.data);
-        if (mode.mode != SPICE_AUDIO_DATA_MODE_OPUS)
-        {
-            this.log_err('This player cannot handle mode ' + mode.mode);
-            delete this.source_buffer;
-        }
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_PLAYBACK_STOP)
-    {
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_PLAYBACK_VOLUME)
-    {
-        this.known_unimplemented(msg.type, "Playback Volume");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_PLAYBACK_MUTE)
-    {
-        this.known_unimplemented(msg.type, "Playback Mute");
-        return true;
-    }
-
-    if (msg.type == SPICE_MSG_PLAYBACK_LATENCY)
-    {
-        this.known_unimplemented(msg.type, "Playback Latency");
-        return true;
-    }
-
-    return false;
-}
-
-SpicePlaybackConn.prototype.start_playback = function(data)
-{
-    this.start_time = data.time;
-
-    var h = new webm_Header();
-    var te = new webm_AudioTrackEntry;
-    var t = new webm_Tracks(te);
-
-    var mb = new ArrayBuffer(h.buffer_size() + t.buffer_size())
-
-    this.bytes_written = h.to_buffer(mb);
-    this.bytes_written = t.to_buffer(mb, this.bytes_written);
-
-    this.source_buffer.addEventListener('error', handle_sourcebuffer_error, false);
-    this.source_buffer.addEventListener('updateend', handle_append_buffer_done, false);
-    playback_append_buffer(this, mb);
-
-    this.new_cluster(data);
-}
-
-SpicePlaybackConn.prototype.new_cluster = function(data)
-{
-    this.cluster_time = data.time;
-
-    var c = new webm_Cluster(data.time - this.start_time - this.gap_time);
-
-    var mb = new ArrayBuffer(c.buffer_size());
-    this.bytes_written += c.to_buffer(mb);
-
-    if (this.append_okay)
-        playback_append_buffer(this, mb);
-    else
-        this.queue.push(mb);
-
-    this.simple_block(data, true);
-}
-
-SpicePlaybackConn.prototype.simple_block = function(data, keyframe)
-{
-    var sb = new webm_SimpleBlock(data.time - this.cluster_time, data.data, keyframe);
-    var mb = new ArrayBuffer(sb.buffer_size());
-
-    this.bytes_written += sb.to_buffer(mb);
-
-    if (this.append_okay)
-        playback_append_buffer(this, mb);
-    else
-        this.queue.push(mb);
-}
-
-function handle_source_open(e)
-{
-    var p = this.spiceconn;
-
-    if (p.source_buffer)
-        return;
-
-    p.source_buffer = this.addSourceBuffer(SPICE_PLAYBACK_CODEC);
-    if (! p.source_buffer)
-    {
-        p.log_err('Codec ' + SPICE_PLAYBACK_CODEC + ' not available.');
-        return;
-    }
-
-    if (PLAYBACK_DEBUG > 0)
-        playback_handle_event_debug.call(this, e);
-
-    listen_for_audio_events(p);
-
-    p.source_buffer.spiceconn = p;
-    p.source_buffer.mode = "segments";
-
-    // FIXME - Experimentation with segments and sequences was unsatisfying.
-    //         Switching to sequence did not solve our gap problem,
-    //         but the browsers didn't fully support the time seek capability
-    //         we would expect to gain from 'segments'.
-    //         Segments worked at the time of this patch, so segments it is for now.
-
-}
-
-function handle_source_ended(e)
-{
-    var p = this.spiceconn;
-    p.log_err('Audio source unexpectedly ended.');
-}
-
-function handle_source_closed(e)
-{
-    var p = this.spiceconn;
-    p.log_err('Audio source unexpectedly closed.');
-}
-
-function handle_append_buffer_done(e)
-{
-    var p = this.spiceconn;
-
-    if (PLAYBACK_DEBUG > 1)
-        playback_handle_event_debug.call(this, e);
-
-    if (p.queue.length > 0)
-    {
-        var mb = p.queue.shift();
-        playback_append_buffer(p, mb);
-    }
-    else
-        p.append_okay = true;
-
-}
-
-function handle_sourcebuffer_error(e)
-{
-    var p = this.spiceconn;
-    p.log_err('source_buffer error ' + e.message);
-}
-
-function playback_append_buffer(p, b)
-{
-    try
-    {
-        p.source_buffer.appendBuffer(b);
-        p.append_okay = false;
-    }
-    catch (e)
-    {
-        p.log_err("Error invoking appendBuffer: " + e.message);
-    }
-}
-
-function playback_handle_event_debug(e)
-{
-    var p = this.spiceconn;
-    if (p.audio)
-    {
-        if (PLAYBACK_DEBUG > 0 || p.audio.buffered.len > 1)
-            console.log(p.audio.currentTime + ": event " + e.type +
-                dump_media_element(p.audio));
-    }
-
-    if (PLAYBACK_DEBUG > 1 && p.media_source)
-        console.log("  media_source " + dump_media_source(p.media_source));
-
-    if (PLAYBACK_DEBUG > 1 && p.source_buffer)
-        console.log("  source_buffer " + dump_source_buffer(p.source_buffer));
-
-    if (PLAYBACK_DEBUG > 0 || p.queue.length > 1)
-        console.log('  queue len ' + p.queue.length + '; append_okay: ' + p.append_okay);
-}
-
-function playback_debug_listen_for_one_event(name)
-{
-    this.addEventListener(name, playback_handle_event_debug);
-}
-
-function listen_for_audio_events(spiceconn)
-{
-    var audio_0_events = [
-        "abort", "error"
-    ];
-
-    var audio_1_events = [
-        "loadstart", "suspend", "emptied", "stalled", "loadedmetadata", "loadeddata", "canplay",
-        "canplaythrough", "playing", "waiting", "seeking", "seeked", "ended", "durationchange",
-        "timeupdate", "play", "pause", "ratechange"
-    ];
-
-    var audio_2_events = [
-        "progress",
-        "resize",
-        "volumechange"
-    ];
-
-    audio_0_events.forEach(playback_debug_listen_for_one_event, spiceconn.audio);
-    if (PLAYBACK_DEBUG > 0)
-        audio_1_events.forEach(playback_debug_listen_for_one_event, spiceconn.audio);
-    if (PLAYBACK_DEBUG > 1)
-        audio_2_events.forEach(playback_debug_listen_for_one_event, spiceconn.audio);
-}
diff -pruN 0.1.7-5/png.js 0.2.2-0ubuntu3/png.js
--- 0.1.7-5/png.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/png.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,256 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  crc logic from rfc2083 ported to Javascript
-**--------------------------------------------------------------------------*/
-
-var rfc2083_crc_table = Array(256);
-var rfc2083_crc_table_computed = 0;
-/* Make the table for a fast CRC. */
-function rfc2083_make_crc_table()
-{
-    var c;
-    var n, k;
-    for (n = 0; n < 256; n++)
-    {
-        c = n;
-        for (k = 0; k < 8; k++)
-        {
-            if (c & 1)
-                c = ((0xedb88320 ^ (c >>> 1)) >>> 0) & 0xffffffff;
-            else
-                c = c >>> 1;
-        }
-        rfc2083_crc_table[n] = c;
-    }
-
-    rfc2083_crc_table_computed = 1;
-}
-
-/* Update a running CRC with the bytes buf[0..len-1]--the CRC
-     should be initialized to all 1's, and the transmitted value
-     is the 1's complement of the final running CRC (see the
-     crc() routine below)). */
-
-function rfc2083_update_crc(crc, u8buf, at, len)
-{
-    var c = crc;
-    var n;
-
-    if (!rfc2083_crc_table_computed)
-        rfc2083_make_crc_table();
-
-    for (n = 0; n < len; n++)
-    {
-        c = rfc2083_crc_table[(c ^ u8buf[at + n]) & 0xff] ^ (c >>> 8);
-    }
-
-    return c;
-}
-
-function rfc2083_crc(u8buf, at, len)
-{
-    return rfc2083_update_crc(0xffffffff, u8buf, at, len) ^ 0xffffffff;
-}
-
-function crc32(mb, at, len)
-{
-    var u8 = new Uint8Array(mb);
-    return rfc2083_crc(u8, at, len);
-}
-
-function PngIHDR(width, height)
-{
-    this.width = width;
-    this.height = height;
-    this.depth = 8;
-    this.type = 6;
-    this.compression = 0;
-    this.filter = 0;
-    this.interlace = 0;
-}
-
-PngIHDR.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var orig = at;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.buffer_size() - 12); at += 4;
-        dv.setUint8(at, 'I'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'H'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'D'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'R'.charCodeAt(0)); at++;
-        dv.setUint32(at, this.width); at += 4;
-        dv.setUint32(at, this.height); at += 4;
-        dv.setUint8(at, this.depth); at++;
-        dv.setUint8(at, this.type); at++;
-        dv.setUint8(at, this.compression); at++;
-        dv.setUint8(at, this.filter); at++;
-        dv.setUint8(at, this.interlace); at++;
-        dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 12 + 13;
-    }
-}
-
-
-function adler()
-{
-    this.s1 = 1;
-    this.s2 = 0;
-}
-
-adler.prototype.update = function(b)
-{
-    this.s1 += b;
-    this.s1 %= 65521;
-    this.s2 += this.s1;
-    this.s2 %= 65521;
-}
-
-function PngIDAT(width, height, bytes)
-{
-    if (bytes.byteLength > 65535)
-    {
-        throw new Error("Cannot handle more than 64K");
-    }
-    this.data = bytes;
-    this.width = width;
-    this.height = height;
-}
-
-PngIDAT.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var orig = at;
-        var x, y, i, j;
-        var dv = new SpiceDataView(a);
-        var zsum = new adler();
-        dv.setUint32(at, this.buffer_size() - 12); at += 4;
-        dv.setUint8(at, 'I'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'D'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'A'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'T'.charCodeAt(0)); at++;
-
-        /* zlib header.  */
-        dv.setUint8(at, 0x78); at++;
-        dv.setUint8(at, 0x01); at++;
-
-        /* Deflate header.  Specifies uncompressed, final bit */
-        dv.setUint8(at, 0x80); at++;
-        dv.setUint16(at, this.data.byteLength + this.height); at += 2;
-        dv.setUint16(at, ~(this.data.byteLength + this.height)); at += 2;
-        var u8 = new Uint8Array(this.data);
-        for (i = 0, y = 0; y < this.height; y++)
-        {
-            /* Filter type 0 - uncompressed */
-            dv.setUint8(at, 0); at++;
-            zsum.update(0);
-            for (x = 0; x < this.width && i < this.data.byteLength; x++)
-            {
-                zsum.update(u8[i]);
-                dv.setUint8(at, u8[i++]); at++;
-                zsum.update(u8[i]);
-                dv.setUint8(at, u8[i++]); at++;
-                zsum.update(u8[i]);
-                dv.setUint8(at, u8[i++]); at++;
-                zsum.update(u8[i]);
-                dv.setUint8(at, u8[i++]); at++;
-            }
-        }
-
-        /* zlib checksum.   */
-        dv.setUint16(at, zsum.s2); at+=2;
-        dv.setUint16(at, zsum.s1); at+=2;
-
-        /* FIXME - something is not quite right with the zlib code;
-                   you get an error from libpng if you open the image in
-                   gimp.  But it works, so it's good enough for now... */
-
-        dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 12 + this.data.byteLength + this.height + 4 + 2 + 1 + 2 + 2;
-    }
-}
-
-
-function PngIEND()
-{
-}
-
-PngIEND.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var orig = at;
-        var i;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.buffer_size() - 12); at += 4;
-        dv.setUint8(at, 'I'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'E'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'N'.charCodeAt(0)); at++;
-        dv.setUint8(at, 'D'.charCodeAt(0)); at++;
-        dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 12;
-    }
-}
-
-
-function create_rgba_png(width, height, bytes)
-{
-    var i;
-    var ihdr = new PngIHDR(width, height);
-    var idat = new PngIDAT(width, height, bytes);
-    var iend = new PngIEND;
-
-    var mb = new ArrayBuffer(ihdr.buffer_size() + idat.buffer_size() + iend.buffer_size());
-    var at = ihdr.to_buffer(mb);
-    at = idat.to_buffer(mb, at);
-    at = iend.to_buffer(mb, at);
-
-    var u8 = new Uint8Array(mb);
-    var str = "";
-    for (i = 0; i < at; i++)
-    {
-        str += "%";
-        if (u8[i] < 16)
-            str += "0";
-        str += u8[i].toString(16);
-    }
-
-
-    return "%89PNG%0D%0A%1A%0A" + str;
-}
diff -pruN 0.1.7-5/quic.js 0.2.2-0ubuntu3/quic.js
--- 0.1.7-5/quic.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/quic.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,1336 +0,0 @@
-/*"use strict";*/
-/* use strict is commented out because it results in a 5x slowdone in chrome */
-/*
- *    Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
- *    Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com>
- *
- *    This file is part of spice-html5.
- *
- *    spice-html5 is free software: you can redistribute it and/or modify
- *    it under the terms of the GNU Lesser General Public License as published by
- *    the Free Software Foundation, either version 3 of the License, or
- *    (at your option) any later version.
- *
- *    spice-html5 is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU Lesser General Public License for more details.
- *
- *    You should have received a copy of the GNU Lesser General Public License
- *    along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-var encoder;
-
-var QUIC_IMAGE_TYPE_INVALID = 0;
-var QUIC_IMAGE_TYPE_GRAY = 1;
-var QUIC_IMAGE_TYPE_RGB16 = 2;
-var QUIC_IMAGE_TYPE_RGB24 = 3;
-var QUIC_IMAGE_TYPE_RGB32 = 4;
-var QUIC_IMAGE_TYPE_RGBA = 5;
-var DEFevol = 3;
-var DEFwmimax = 6;
-var DEFwminext = 2048;
-var need_init = true;
-var DEFmaxclen = 26;
-var evol = DEFevol;
-var wmimax = DEFwmimax;
-var wminext = DEFwminext;
-var family_5bpc = { nGRcodewords:[0,0,0,0,0,0,0,0],
-                    notGRcwlen:[0,0,0,0,0,0,0,0],
-                    notGRprefixmask:[0,0,0,0,0,0,0,0],
-                    notGRsuffixlen:[0,0,0,0,0,0,0,0],
-                    xlatU2L:[0,0,0,0,0,0,0,0],
-                    xlatL2U:[0,0,0,0,0,0,0,0]
-                  };
-var family_8bpc = { nGRcodewords:[0,0,0,0,0,0,0,0],
-                    notGRcwlen:[0,0,0,0,0,0,0,0],
-                    notGRprefixmask:[0,0,0,0,0,0,0,0],
-                    notGRsuffixlen:[0,0,0,0,0,0,0,0],
-                    xlatU2L:[0,0,0,0,0,0,0,0],
-                    xlatL2U:[0,0,0,0,0,0,0,0]
-                  };
-var bppmask = [ 0x00000000,
-    0x00000001, 0x00000003, 0x00000007, 0x0000000f,
-    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
-    0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
-    0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
-    0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
-    0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
-    0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
-    0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff];
-
-var zeroLUT = [];
-
-var besttrigtab = [
-            [ 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160],
-            [ 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140],
-            [ 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160]];
-
-var J = [ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6,
-          7, 7, 8, 9, 10, 11, 12, 13, 14, 15];
-
-var lzeroes = [
-    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-    3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0];
-
-var tabrand_chaos = [
-    0x02c57542, 0x35427717, 0x2f5a2153, 0x9244f155, 0x7bd26d07, 0x354c6052,
-    0x57329b28, 0x2993868e, 0x6cd8808c, 0x147b46e0, 0x99db66af, 0xe32b4cac,
-    0x1b671264, 0x9d433486, 0x62a4c192, 0x06089a4b, 0x9e3dce44, 0xdaabee13,
-    0x222425ea, 0xa46f331d, 0xcd589250, 0x8bb81d7f, 0xc8b736b9, 0x35948d33,
-    0xd7ac7fd0, 0x5fbe2803, 0x2cfbc105, 0x013dbc4e, 0x7a37820f, 0x39f88e9e,
-    0xedd58794, 0xc5076689, 0xfcada5a4, 0x64c2f46d, 0xb3ba3243, 0x8974b4f9,
-    0x5a05aebd, 0x20afcd00, 0x39e2b008, 0x88a18a45, 0x600bde29, 0xf3971ace,
-    0xf37b0a6b, 0x7041495b, 0x70b707ab, 0x06beffbb, 0x4206051f, 0xe13c4ee3,
-    0xc1a78327, 0x91aa067c, 0x8295f72a, 0x732917a6, 0x1d871b4d, 0x4048f136,
-    0xf1840e7e, 0x6a6048c1, 0x696cb71a, 0x7ff501c3, 0x0fc6310b, 0x57e0f83d,
-    0x8cc26e74, 0x11a525a2, 0x946934c7, 0x7cd888f0, 0x8f9d8604, 0x4f86e73b,
-    0x04520316, 0xdeeea20c, 0xf1def496, 0x67687288, 0xf540c5b2, 0x22401484,
-    0x3478658a, 0xc2385746, 0x01979c2c, 0x5dad73c8, 0x0321f58b, 0xf0fedbee,
-    0x92826ddf, 0x284bec73, 0x5b1a1975, 0x03df1e11, 0x20963e01, 0xa17cf12b,
-    0x740d776e, 0xa7a6bf3c, 0x01b5cce4, 0x1118aa76, 0xfc6fac0a, 0xce927e9b,
-    0x00bf2567, 0x806f216c, 0xbca69056, 0x795bd3e9, 0xc9dc4557, 0x8929b6c2,
-    0x789d52ec, 0x3f3fbf40, 0xb9197368, 0xa38c15b5, 0xc3b44fa8, 0xca8333b0,
-    0xb7e8d590, 0xbe807feb, 0xbf5f8360, 0xd99e2f5c, 0x372928e1, 0x7c757c4c,
-    0x0db5b154, 0xc01ede02, 0x1fc86e78, 0x1f3985be, 0xb4805c77, 0x00c880fa,
-    0x974c1b12, 0x35ab0214, 0xb2dc840d, 0x5b00ae37, 0xd313b026, 0xb260969d,
-    0x7f4c8879, 0x1734c4d3, 0x49068631, 0xb9f6a021, 0x6b863e6f, 0xcee5debf,
-    0x29f8c9fb, 0x53dd6880, 0x72b61223, 0x1f67a9fd, 0x0a0f6993, 0x13e59119,
-    0x11cca12e, 0xfe6b6766, 0x16b6effc, 0x97918fc4, 0xc2b8a563, 0x94f2f741,
-    0x0bfa8c9a, 0xd1537ae8, 0xc1da349c, 0x873c60ca, 0x95005b85, 0x9b5c080e,
-    0xbc8abbd9, 0xe1eab1d2, 0x6dac9070, 0x4ea9ebf1, 0xe0cf30d4, 0x1ef5bd7b,
-    0xd161043e, 0x5d2fa2e2, 0xff5d3cae, 0x86ed9f87, 0x2aa1daa1, 0xbd731a34,
-    0x9e8f4b22, 0xb1c2c67a, 0xc21758c9, 0xa182215d, 0xccb01948, 0x8d168df7,
-    0x04238cfe, 0x368c3dbc, 0x0aeadca5, 0xbad21c24, 0x0a71fee5, 0x9fc5d872,
-    0x54c152c6, 0xfc329483, 0x6783384a, 0xeddb3e1c, 0x65f90e30, 0x884ad098,
-    0xce81675a, 0x4b372f7d, 0x68bf9a39, 0x43445f1e, 0x40f8d8cb, 0x90d5acb6,
-    0x4cd07282, 0x349eeb06, 0x0c9d5332, 0x520b24ef, 0x80020447, 0x67976491,
-    0x2f931ca3, 0xfe9b0535, 0xfcd30220, 0x61a9e6cc, 0xa487d8d7, 0x3f7c5dd1,
-    0x7d0127c5, 0x48f51d15, 0x60dea871, 0xc9a91cb7, 0x58b53bb3, 0x9d5e0b2d,
-    0x624a78b4, 0x30dbee1b, 0x9bdf22e7, 0x1df5c299, 0x2d5643a7, 0xf4dd35ff,
-    0x03ca8fd6, 0x53b47ed8, 0x6f2c19aa, 0xfeb0c1f4, 0x49e54438, 0x2f2577e6,
-    0xbf876969, 0x72440ea9, 0xfa0bafb8, 0x74f5b3a0, 0x7dd357cd, 0x89ce1358,
-    0x6ef2cdda, 0x1e7767f3, 0xa6be9fdb, 0x4f5f88f8, 0xba994a3a, 0x08ca6b65,
-    0xe0893818, 0x9e00a16a, 0xf42bfc8f, 0x9972eedc, 0x749c8b51, 0x32c05f5e,
-    0xd706805f, 0x6bfbb7cf, 0xd9210a10, 0x31a1db97, 0x923a9559, 0x37a7a1f6,
-    0x059f8861, 0xca493e62, 0x65157e81, 0x8f6467dd, 0xab85ff9f, 0x9331aff2,
-    0x8616b9f5, 0xedbd5695, 0xee7e29b1, 0x313ac44f, 0xb903112f, 0x432ef649,
-    0xdc0a36c0, 0x61cf2bba, 0x81474925, 0xa8b6c7ad, 0xee5931de, 0xb2f8158d,
-    0x59fb7409, 0x2e3dfaed, 0x9af25a3f, 0xe1fed4d5 ];
-
-var rgb32_pixel_pad = 3;
-var rgb32_pixel_r = 2;
-var rgb32_pixel_g = 1;
-var rgb32_pixel_b = 0;
-var rgb32_pixel_size = 4;
-
-/* Helper Functions */
-
-function ceil_log_2(val)
-{
-    if (val === 1)
-        return 0;
-
-    var result = 1;
-    val -= 1;
-    while (val = val >>> 1)
-        result++;
-
-    return result;
-}
-
-function family_init(family, bpc, limit)
-{
-    var l;
-    for (l = 0; l < bpc; l++)
-    {
-        var altprefixlen, altcodewords;
-        altprefixlen = limit - bpc;
-        if (altprefixlen > bppmask[bpc - l])
-            altprefixlen = bppmask[bpc - l];
-
-        altcodewords = bppmask[bpc] + 1 - (altprefixlen << l);
-        family.nGRcodewords[l] = (altprefixlen << l);
-        family.notGRcwlen[l] = altprefixlen + ceil_log_2(altcodewords);
-        family.notGRprefixmask[l] = bppmask[32 - altprefixlen]>>>0;
-        family.notGRsuffixlen[l] = ceil_log_2(altcodewords);
-    }
-
-    /* decorelate_init */
-    var pixelbitmask = bppmask[bpc];
-    var pixelbitmaskshr = pixelbitmask >>> 1;
-    var s;
-    for (s = 0; s <= pixelbitmask; s++) {
-        if (s <= pixelbitmaskshr) {
-            family.xlatU2L[s] = s << 1;
-        } else {
-            family.xlatU2L[s] = ((pixelbitmask - s) << 1) + 1;
-        }
-    }
-
-    /* corelate_init */
-    for (s = 0; s <= pixelbitmask; s++) {
-        if (s & 0x01) {
-            family.xlatL2U[s] = pixelbitmask - (s >>> 1);
-        } else {
-            family.xlatL2U[s] = (s >>> 1);
-        }
-    }
-}
-
-function quic_image_bpc(type)
-{
-    switch (type) {
-    case QUIC_IMAGE_TYPE_GRAY:
-        return 8;
-    case QUIC_IMAGE_TYPE_RGB16:
-        return 5;
-    case QUIC_IMAGE_TYPE_RGB24:
-        return 8;
-    case QUIC_IMAGE_TYPE_RGB32:
-        return 8;
-    case QUIC_IMAGE_TYPE_RGBA:
-        return 8;
-    case QUIC_IMAGE_TYPE_INVALID:
-    default:
-        console.log("quic: bad image type\n");
-        return 0;
-    }
-}
-
-function cnt_l_zeroes(bits)
-{
-    if (bits & 0xff800000) {
-        return lzeroes[bits >>> 24];
-    } else if (bits & 0xffff8000) {
-        return 8 + lzeroes[(bits >>> 16) & 0x000000ff];
-    } else if (bits & 0xffffff80) {
-        return 16 + lzeroes[(bits >>> 8) & 0x000000ff];
-    } else {
-        return 24 + lzeroes[bits & 0x000000ff];
-    }
-}
-
-function golomb_decoding_8bpc(l, bits)
-{
-    var rc;
-    var cwlen;
-
-    if (bits < 0 || bits > family_8bpc.notGRprefixmask[l])
-    {
-        var zeroprefix = cnt_l_zeroes(bits);
-        cwlen = zeroprefix + 1 + l;
-        rc = (zeroprefix << l) | (bits >> (32-cwlen)) & bppmask[l];
-    }
-    else
-    {
-        cwlen = family_8bpc.notGRcwlen[l];
-        rc = family_8bpc.nGRcodewords[l] + ((bits >> (32-cwlen)) & bppmask[family_8bpc.notGRsuffixlen[l]]);
-    }
-    return {'codewordlen':cwlen, 'rc':rc};
-}
-
-function golomb_code_len_8bpc(n, l)
-{
-    if (n < family_8bpc.nGRcodewords[l]) {
-        return (n >>> l) + 1 + l;
-    } else {
-        return family_8bpc.notGRcwlen[l];
-    }
-}
-
-function QuicModel(bpc)
-{
-    var bstart;
-    var bend = 0;
-
-    this.levels = 0x1 << bpc;
-    this.n_buckets_ptrs = 0;
-
-    switch (evol) {
-        case 1:
-            this.repfirst = 3;
-            this.firstsize = 1;
-            this.repnext = 2;
-            this.mulsize = 2;
-            break;
-        case 3:
-            this.repfirst = 1;
-            this.firstsize = 1;
-            this.repnext = 1;
-            this.mulsize = 2;
-            break;
-        case 5:
-            this.repfirst = 1;
-            this.firstsize = 1;
-            this.repnext = 1;
-            this.mulsize = 4;
-            break;
-        case 0:
-        case 2:
-        case 4:
-            console.log("quic: findmodelparams(): evol value obsolete!!!\n");
-            break;
-        default:
-            console.log("quic: findmodelparams(): evol out of range!!!\n");
-    }
-
-    this.n_buckets = 0;
-    var repcntr = this.repfirst + 1;
-    var bsize = this.firstsize;
-
-    do {
-        if (this.n_buckets) {
-            bstart = bend + 1;
-        } else {
-            bstart = 0;
-        }
-
-        if (!--repcntr) {
-            repcntr = this.repnext;
-            bsize *= this.mulsize;
-        }
-
-        bend = bstart + bsize - 1;
-        if (bend + bsize >= this.levels) {
-            bend = this.levels - 1;
-        }
-
-        if (!this.n_buckets_ptrs) {
-            this.n_buckets_ptrs = this.levels;
-        }
-
-        (this.n_buckets)++;
-    } while (bend < this.levels - 1);
-}
-
-QuicModel.prototype = {
-    n_buckets : 0,
-    n_buckets_ptrs : 0,
-    repfirst : 0,
-    firstsize : 0,
-    repnext : 0,
-    mulsize : 0,
-    levels :0
-}
-
-function QuicBucket()
-{
-    this.counters = [0,0,0,0,0,0,0,0];
-}
-
-QuicBucket.prototype = {
-    bestcode: 0,
-
-    reste : function (bpp)
-    {
-        this.bestcode = bpp;
-        this.counters = [0,0,0,0,0,0,0,0];
-    },
-
-    update_model_8bpc : function (state, curval, bpp)
-    {
-        var i;
-
-        var bestcode = bpp - 1;
-        var bestcodelen = (this.counters[bestcode] += golomb_code_len_8bpc(curval, bestcode));
-
-        for (i = bpp - 2; i >= 0; i--) {
-            var ithcodelen = (this.counters[i] += golomb_code_len_8bpc(curval, i));
-
-            if (ithcodelen < bestcodelen) {
-                bestcode = i;
-                bestcodelen = ithcodelen;
-            }
-        }
-
-        this.bestcode = bestcode;
-
-        if (bestcodelen > state.wm_trigger) {
-            for (i = 0; i < bpp; i++) {
-                this.counters[i] = this.counters[i] >>> 1;
-            }
-        }
-    }
-}
-
-function QuicFamilyStat()
-{
-    this.buckets_ptrs = [];
-    this.buckets_buf = [];
-}
-
-QuicFamilyStat.prototype = {
-
-    fill_model_structures : function(model)
-    {
-        var bstart;
-        var bend = 0;
-        var bnumber = 0;
-
-        var repcntr = model.repfirst + 1;
-        var bsize = model.firstsize;
-
-        do {
-            if (bnumber) {
-                bstart = bend + 1;
-            } else {
-                bstart = 0;
-            }
-
-            if (!--repcntr) {
-                repcntr = model.repnext;
-                bsize *= model.mulsize;
-            }
-
-            bend = bstart + bsize - 1;
-            if (bend + bsize >= model.levels) {
-                bend = model.levels - 1;
-            }
-
-            this.buckets_buf[bnumber] = new QuicBucket;
-
-            var i;
-            for (i = bstart; i <= bend; i++) {
-                this.buckets_ptrs[i] = this.buckets_buf[bnumber];
-            }
-
-            bnumber++;
-        } while (bend < model.levels - 1);
-        return true;
-    }
-}
-
-function QuicChannel(model_8bpc, model_5bpc)
-{
-    this.state = new CommonState;
-    this.family_stat_8bpc = new QuicFamilyStat;
-    this.family_stat_5bpc = new QuicFamilyStat;
-    this.correlate_row = { zero: 0 , row:[] };
-    this.model_8bpc = model_8bpc;
-    this.model_5bpc = model_5bpc;
-    this.buckets_ptrs = [];
-
-    if (!this.family_stat_8bpc.fill_model_structures(this.model_8bpc))
-        return undefined;
-
-    if (!this.family_stat_5bpc.fill_model_structures(this.model_5bpc))
-        return undefined;
-}
-
-QuicChannel.prototype = {
-
-    reste : function (bpc)
-    {
-        var j;
-        this.correlate_row = { zero: 0 , row: []};
-
-        if (bpc == 8) {
-            for (j = 0; j < this.model_8bpc.n_buckets; j++)
-                this.family_stat_8bpc.buckets_buf[j].reste(7);
-            this.buckets_ptrs = this.family_stat_8bpc.buckets_ptrs;
-        } else if (bpc == 5) {
-            for (j = 0; j < this.model_5bpc.n_buckets; j++)
-                this.family_stat_8bpc.buckets_buf[j].reste(4);
-            this.buckets_ptrs = this.family_stat_5bpc.buckets_ptrs;
-        } else {
-            console.log("quic: %s: bad bpc %d\n", __FUNCTION__, bpc);
-            return false;
-        }
-
-        this.state.reste();
-        return true;
-    }
-}
-
-function CommonState()
-{
-}
-
-CommonState.prototype = {
-    waitcnt: 0,
-    tabrand_seed: 0xff,
-    wm_trigger: 0,
-    wmidx: 0,
-    wmileft: wminext,
-    melcstate: 0,
-    melclen: 0,
-    melcorder: 0,
-
-    set_wm_trigger : function()
-    {
-        var wm = this.wmidx;
-        if (wm > 10) {
-            wm = 10;
-        }
-
-        this.wm_trigger = besttrigtab[Math.floor(evol / 2)][wm];
-    },
-
-    reste : function()
-    {
-        this.waitcnt = 0;
-        this.tabrand_seed = 0x0ff;
-        this.wmidx = 0;
-        this.wmileft = wminext;
-
-        this.set_wm_trigger();
-
-        this.melcstate = 0;
-        this.melclen = J[0];
-        this.melcorder = 1 << this.melclen;
-    },
-
-    tabrand : function()
-    {
-        this.tabrand_seed++;
-        return tabrand_chaos[this.tabrand_seed & 0x0ff];
-    }
-}
-
-
-function QuicEncoder()
-{
-    this.rgb_state = new CommonState;
-    this.model_8bpc = new QuicModel(8);
-    this.model_5bpc = new QuicModel(5);
-    this.channels = [];
-
-    var i;
-    for (i = 0; i < 4; i++) {
-        this.channels[i] = new QuicChannel(this.model_8bpc, this.model_5bpc);
-        if (!this.channels[i])
-        {
-            console.log("quic: failed to create channel");
-            return undefined;
-        }
-    }
-}
-
-QuicEncoder.prototype = {
-                    type: 0,
-                    width: 0,
-                    height: 0,
-                    io_idx: 0,
-                    io_available_bits: 0,
-                    io_word: 0,
-                    io_next_word: 0,
-                    io_now: 0,
-                    io_end: 0,
-                    rows_completed: 0,
-              };
-
-QuicEncoder.prototype.reste = function(io_ptr)
-{
-    this.rgb_state.reste();
-
-    this.io_now = io_ptr;
-    this.io_end = this.io_now.length;
-    this.io_idx = 0;
-    this.rows_completed = 0;
-    return true;
-}
-
-QuicEncoder.prototype.read_io_word = function()
-{
-    if (this.io_idx >= this.io_end)
-        throw("quic: out of data");
-    this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24;
-}
-
-QuicEncoder.prototype.decode_eatbits = function (len)
-{
-    this.io_word = this.io_word << len;
-
-    var delta = (this.io_available_bits - len);
-    if (delta >= 0)
-    {
-        this.io_available_bits = delta;
-        this.io_word |= this.io_next_word >>> this.io_available_bits;
-    }
-    else
-    {
-        delta = -1 * delta;
-        this.io_word |= this.io_next_word << delta;
-        this.read_io_word();
-        this.io_available_bits = 32 - delta;
-        this.io_word |= this.io_next_word >>> this.io_available_bits;
-    }
-}
-
-QuicEncoder.prototype.decode_eat32bits = function()
-{
-    this.decode_eatbits(16);
-    this.decode_eatbits(16);
-}
-
-QuicEncoder.prototype.reste_channels = function(bpc)
-{
-    var i;
-
-    for (i = 0; i < 4; i++)
-        if (!this.channels[i].reste(bpc))
-            return false;
-    return true;
-}
-
-QuicEncoder.prototype.quic_decode_begin = function(io_ptr)
-{
-    if (!this.reste(io_ptr)) {
-        return false;
-    }
-
-    this.io_idx = 0;
-    this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24;
-    this.io_word = this.io_next_word;
-    this.io_available_bits = 0;
-
-    var magic = this.io_word;
-    this.decode_eat32bits();
-    if (magic != 0x43495551) /*QUIC*/ {
-        console.log("quic: bad magic "+magic.toString(16));
-        return false;
-    }
-
-    var version = this.io_word;
-    this.decode_eat32bits();
-    if (version != ((0 << 16) | (0 & 0xffff))) {
-        console.log("quic: bad version "+version.toString(16));
-        return false;
-    }
-
-    this.type = this.io_word;
-    this.decode_eat32bits();
-
-    this.width = this.io_word;
-    this.decode_eat32bits();
-
-    this.height = this.io_word;
-    this.decode_eat32bits();
-
-    var bpc = quic_image_bpc(this.type);
-
-    if (!this.reste_channels(bpc))
-        return false;
-
-    return true;
-}
-
-QuicEncoder.prototype.quic_rgb32_uncompress_row0_seg = function (i, cur_row, end,
-                                       waitmask, bpc, bpc_mask)
-{
-    var stopidx;
-    var n_channels = 3;
-    var c;
-    var a;
-
-    if (!i) {
-        cur_row[rgb32_pixel_pad] = 0;
-        c = 0;
-        do
-        {
-            a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word);
-            this.channels[c].correlate_row.row[0] = a.rc;
-            cur_row[2-c] = (family_8bpc.xlatL2U[a.rc]&0xFF);
-            this.decode_eatbits(a.codewordlen);
-        } while (++c < n_channels);
-
-        if (this.rgb_state.waitcnt) {
-            --this.rgb_state.waitcnt;
-        } else {
-            this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask);
-            c = 0;
-            do
-            {
-                this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc);
-            } while (++c < n_channels);
-        }
-        stopidx = ++i + this.rgb_state.waitcnt;
-    } else {
-        stopidx = i + this.rgb_state.waitcnt;
-    }
-
-    while (stopidx < end) {
-        for (; i <= stopidx; i++) {
-            cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0;
-            c = 0;
-            do
-            {
-                a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word);
-                this.channels[c].correlate_row.row[i] = a.rc;
-                cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask;
-                this.decode_eatbits(a.codewordlen);
-            } while (++c < n_channels);
-        }
-        c = 0;
-        do
-        {
-            this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc);
-        } while (++c < n_channels);
-        stopidx = i + (this.rgb_state.tabrand() & waitmask);
-    }
-
-    for (; i < end; i++) {
-        cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0;
-        c = 0;
-        do
-        {
-            a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word);
-            this.channels[c].correlate_row.row[i] = a.rc;
-            cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask;
-            this.decode_eatbits(a.codewordlen);
-        } while (++c < n_channels);
-    }
-    this.rgb_state.waitcnt = stopidx - end;
-}
-
-QuicEncoder.prototype.quic_rgb32_uncompress_row0 = function (cur_row)
-{
-    var bpc = 8;
-    var bpc_mask = 0xff;
-    var pos = 0;
-    var width = this.width;
-
-    while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) {
-        if (this.rgb_state.wmileft) {
-            this.quic_rgb32_uncompress_row0_seg(pos, cur_row,
-                                       pos + this.rgb_state.wmileft,
-                                       bppmask[this.rgb_state.wmidx],
-                                       bpc, bpc_mask);
-            pos += this.rgb_state.wmileft;
-            width -= this.rgb_state.wmileft;
-        }
-
-        this.rgb_state.wmidx++;
-        this.rgb_state.set_wm_trigger();
-        this.rgb_state.wmileft = wminext;
-    }
-
-    if (width) {
-        this.quic_rgb32_uncompress_row0_seg(pos, cur_row, pos + width,
-                                   bppmask[this.rgb_state.wmidx], bpc, bpc_mask);
-        if (wmimax > this.rgb_state.wmidx) {
-            this.rgb_state.wmileft -= width;
-        }
-    }
-}
-
-QuicEncoder.prototype.quic_rgb32_uncompress_row_seg = function( prev_row, cur_row, i, end, bpc, bpc_mask)
-{
-    var n_channels = 3;
-    var waitmask = bppmask[this.rgb_state.wmidx];
-
-    var a;
-    var run_index = 0;
-    var stopidx = 0;
-    var run_end = 0;
-    var c;
-
-    if (!i)
-    {
-        cur_row[rgb32_pixel_pad] = 0;
-
-        c = 0;
-        do {
-            a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word);
-            this.channels[c].correlate_row.row[0] = a.rc;
-            cur_row[2-c] = (family_8bpc.xlatL2U[this.channels[c].correlate_row.row[0]] + prev_row[2-c]) & bpc_mask;
-            this.decode_eatbits(a.codewordlen);
-        } while (++c < n_channels);
-
-        if (this.rgb_state.waitcnt) {
-            --this.rgb_state.waitcnt;
-        } else {
-            this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask);
-            c = 0;
-            do {
-                this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc);
-            } while (++c < n_channels);
-        }
-        stopidx = ++i + this.rgb_state.waitcnt;
-    } else {
-        stopidx = i + this.rgb_state.waitcnt;
-    }
-    for (;;) {
-        var rc = 0;
-        while (stopidx < end && !rc) {
-            for (; i <= stopidx && !rc; i++) {
-                var pixel = i * rgb32_pixel_size;
-                var pixelm1 = (i-1) * rgb32_pixel_size;
-                var pixelm2 = (i-2) * rgb32_pixel_size;
-
-                if ( prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1 + rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b])
-                {
-                    if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b]))
-                    {
-                        /* do run */
-                        this.rgb_state.waitcnt = stopidx - i;
-                        run_index = i;
-                        run_end = i + this.decode_run(this.rgb_state);
-
-                        for (; i < run_end; i++) {
-                            var pixel = i * rgb32_pixel_size;
-                            var pixelm1 = (i-1) * rgb32_pixel_size;
-                            cur_row[pixel+rgb32_pixel_pad] = 0;
-                            cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r];
-                            cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g];
-                            cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b];
-                        }
-
-                        if (i == end) {
-                            return;
-                        }
-                        else
-                        {
-                            stopidx = i + this.rgb_state.waitcnt;
-                            rc = 1;
-                            break;
-                        }
-                    }
-                }
-
-                c = 0;
-                cur_row[pixel+rgb32_pixel_pad] = 0;
-                do {
-                    var cc = this.channels[c];
-                    var cr = cc.correlate_row;
-
-                    a = golomb_decoding_8bpc(cc.buckets_ptrs[cr.row[i-1]].bestcode, this.io_word);
-                    cr.row[i] = a.rc;
-                cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask;
-                    this.decode_eatbits(a.codewordlen);
-                } while (++c < n_channels);
-            }
-            if (rc)
-                break;
-
-            c = 0;
-            do {
-                this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc);
-            } while (++c < n_channels);
-
-            stopidx = i + (this.rgb_state.tabrand() & waitmask);
-        }
-
-        for (; i < end && !rc; i++) {
-            var pixel = i * rgb32_pixel_size;
-            var pixelm1 = (i-1) * rgb32_pixel_size;
-            var pixelm2 = (i-2) * rgb32_pixel_size;
-
-            if (prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1+rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b])
-            {
-                if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b]))
-                {
-                    /* do run */
-                    this.rgb_state.waitcnt = stopidx - i;
-                    run_index = i;
-                    run_end = i + this.decode_run(this.rgb_state);
-
-                    for (; i < run_end; i++) {
-                        var pixel = i * rgb32_pixel_size;
-                        var pixelm1 = (i-1) * rgb32_pixel_size;
-                        cur_row[pixel+rgb32_pixel_pad] = 0;
-                        cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r];
-                        cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g];
-                        cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b];
-                    }
-
-                    if (i == end) {
-                        return;
-                    }
-                    else
-                    {
-                        stopidx = i + this.rgb_state.waitcnt;
-                        rc = 1;
-                        break;
-                    }
-                }
-            }
-
-            cur_row[pixel+rgb32_pixel_pad] = 0;
-            c = 0;
-            do
-            {
-                a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i-1]].bestcode, this.io_word);
-                this.channels[c].correlate_row.row[i] = a.rc;
-                cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask;
-                this.decode_eatbits(a.codewordlen);
-            } while (++c < n_channels);
-        }
-
-          if (!rc)
-          {
-            this.rgb_state.waitcnt = stopidx - end;
-            return;
-          }
-        }
-}
-
-QuicEncoder.prototype.decode_run = function(state)
-{
-    var runlen = 0;
-
-    do {
-        var hits;
-        var x = (~(this.io_word >>> 24)>>>0)&0xff;
-        var temp = zeroLUT[x];
-
-        for (hits = 1; hits <= temp; hits++) {
-            runlen += state.melcorder;
-
-            if (state.melcstate < 32) {
-                state.melclen = J[++state.melcstate];
-                state.melcorder = (1 << state.melclen);
-            }
-        }
-        if (temp != 8) {
-            this.decode_eatbits(temp + 1);
-
-            break;
-        }
-        this.decode_eatbits(8);
-    } while (true);
-
-    if (state.melclen) {
-        runlen += this.io_word >>> (32 - state.melclen);
-        this.decode_eatbits(state.melclen);
-    }
-
-    if (state.melcstate) {
-        state.melclen = J[--state.melcstate];
-        state.melcorder = (1 << state.melclen);
-    }
-
-    return runlen;
-}
-
-QuicEncoder.prototype.quic_rgb32_uncompress_row = function (prev_row, cur_row)
-{
-    var bpc = 8;
-    var bpc_mask = 0xff;
-    var pos = 0;
-    var width = this.width;
-
-    while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) {
-        if (this.rgb_state.wmileft) {
-            this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos,
-                                      pos + this.rgb_state.wmileft, bpc, bpc_mask);
-            pos += this.rgb_state.wmileft;
-            width -= this.rgb_state.wmileft;
-        }
-
-        this.rgb_state.wmidx++;
-        this.rgb_state.set_wm_trigger();
-        this.rgb_state.wmileft = wminext;
-    }
-
-    if (width) {
-        this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos,
-                                  pos + width, bpc, bpc_mask);
-        if (wmimax > this.rgb_state.wmidx) {
-            this.rgb_state.wmileft -= width;
-        }
-    }
-}
-
-QuicEncoder.prototype.quic_four_uncompress_row0_seg = function (channel, i,
-                                       correlate_row, cur_row, end, waitmask,
-                                       bpc, bpc_mask)
-{
-    var stopidx;
-    var a;
-
-    if (i == 0) {
-        a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word);
-        correlate_row.row[0] = a.rc;
-        cur_row[rgb32_pixel_pad] = family_8bpc.xlatL2U[a.rc];
-        this.decode_eatbits(a.codewordlen);
-
-        if (channel.state.waitcnt) {
-            --channel.state.waitcnt;
-        } else {
-            channel.state.waitcnt = (channel.state.tabrand() & waitmask);
-            channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc);
-        }
-        stopidx = ++i + channel.state.waitcnt;
-    } else {
-        stopidx = i + channel.state.waitcnt;
-    }
-
-    while (stopidx < end) {
-        var pbucket;
-
-        for (; i <= stopidx; i++) {
-            pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]];
-
-            a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word);
-            correlate_row.row[i] = a.rc;
-            cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask;
-            this.decode_eatbits(a.codewordlen);
-        }
-
-        pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc);
-
-        stopidx = i + (channel.state.tabrand() & waitmask);
-    }
-
-    for (; i < end; i++) {
-        a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word);
-
-        correlate_row.row[i] = a.rc;
-        cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask;
-        this.decode_eatbits(a.codewordlen);
-    }
-    channel.state.waitcnt = stopidx - end;
-}
-
-QuicEncoder.prototype.quic_four_uncompress_row0 = function(channel, cur_row)
-{
-    var bpc = 8;
-    var bpc_mask = 0xff;
-    var correlate_row = channel.correlate_row;
-    var pos = 0;
-    var width = this.width;
-
-    while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) {
-        if (channel.state.wmileft) {
-            this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row,
-                                       pos + channel.state.wmileft, bppmask[channel.state.wmidx],
-                                       bpc, bpc_mask);
-            pos += channel.state.wmileft;
-            width -= channel.state.wmileft;
-        }
-
-        channel.state.wmidx++;
-        channel.state.set_wm_trigger();
-        channel.state.wmileft = wminext;
-    }
-
-    if (width) {
-        this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row, pos + width,
-                                   bppmask[channel.state.wmidx], bpc, bpc_mask);
-        if (wmimax > channel.state.wmidx) {
-            channel.state.wmileft -= width;
-        }
-    }
-}
-
-QuicEncoder.prototype.quic_four_uncompress_row_seg = function (channel,
-                                      correlate_row, prev_row, cur_row, i,
-                                      end, bpc, bpc_mask)
-{
-    var waitmask = bppmask[channel.state.wmidx];
-    var stopidx;
-
-    var run_index = 0;
-    var run_end;
-
-    var a;
-
-    if (i == 0) {
-        a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word);
-
-        correlate_row.row[0] = a.rc
-        cur_row[rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + prev_row[rgb32_pixel_pad]) & bpc_mask;
-        this.decode_eatbits(a.codewordlen);
-
-        if (channel.state.waitcnt) {
-            --channel.state.waitcnt;
-        } else {
-            channel.state.waitcnt = (channel.state.tabrand() & waitmask);
-            channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc);
-        }
-        stopidx = ++i + channel.state.waitcnt;
-    } else {
-        stopidx = i + channel.state.waitcnt;
-    }
-    for (;;) {
-        var rc = 0;
-        while (stopidx < end && !rc) {
-            var pbucket;
-            for (; i <= stopidx && !rc; i++) {
-                var pixel = i * rgb32_pixel_size;
-                var pixelm1 = (i-1) * rgb32_pixel_size;
-                var pixelm2 = (i-2) * rgb32_pixel_size;
-
-                if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad])
-                {
-                    if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad])
-                    {
-                        /* do run */
-                        channel.state.waitcnt = stopidx - i;
-                        run_index = i;
-
-                        run_end = i + this.decode_run(channel.state);
-
-                        for (; i < run_end; i++) {
-                            var pixel = i * rgb32_pixel_size;
-                            var pixelm1 = (i-1) * rgb32_pixel_size;
-                            cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad];
-                        }
-
-                        if (i == end) {
-                            return;
-                        }
-                        else
-                        {
-                            stopidx = i + channel.state.waitcnt;
-                            rc = 1;
-                            break;
-                        }
-                    }
-                }
-
-                pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]];
-                a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word);
-                correlate_row.row[i] = a.rc
-                cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask;
-                this.decode_eatbits(a.codewordlen);
-            }
-            if (rc)
-                break;
-
-            pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc);
-
-            stopidx = i + (channel.state.tabrand() & waitmask);
-        }
-
-        for (; i < end && !rc; i++) {
-            var pixel = i * rgb32_pixel_size;
-            var pixelm1 = (i-1) * rgb32_pixel_size;
-            var pixelm2 = (i-2) * rgb32_pixel_size;
-            if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad])
-            {
-                if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad])
-                {
-                    /* do run */
-                    channel.state.waitcnt = stopidx - i;
-                    run_index = i;
-
-                    run_end = i + this.decode_run(channel.state);
-
-                    for (; i < run_end; i++) {
-                        var pixel = i * rgb32_pixel_size;
-                        var pixelm1 = (i-1) * rgb32_pixel_size;
-                        cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad];
-                    }
-
-                    if (i == end) {
-                        return;
-                    }
-                    else
-                    {
-                        stopidx = i + channel.state.waitcnt;
-                        rc = 1;
-                        break;
-                    }
-                }
-            }
-
-            a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word);
-            correlate_row.row[i] = a.rc;
-            cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask;
-            this.decode_eatbits(a.codewordlen);
-        }
-
-        if (!rc)
-        {
-            channel.state.waitcnt = stopidx - end;
-            return;
-        }
-    }
-}
-
-QuicEncoder.prototype.quic_four_uncompress_row = function(channel, prev_row,
-                                                        cur_row)
-{
-    var bpc = 8;
-    var bpc_mask = 0xff;
-    var correlate_row = channel.correlate_row;
-    var pos = 0;
-    var width = this.width;
-
-    while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) {
-        if (channel.state.wmileft) {
-            this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos,
-                                      pos + channel.state.wmileft, bpc, bpc_mask);
-            pos += channel.state.wmileft;
-            width -= channel.state.wmileft;
-        }
-
-        channel.state.wmidx++;
-        channel.state.set_wm_trigger();
-        channel.state.wmileft = wminext;
-    }
-
-    if (width) {
-        this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos,
-                                  pos + width, bpc, bpc_mask);
-        if (wmimax > channel.state.wmidx) {
-            channel.state.wmileft -= width;
-        }
-    }
-}
-
-/* We need to be generating rgb32 or rgba */
-QuicEncoder.prototype.quic_decode = function(buf, stride)
-{
-    var row;
-
-    switch (this.type)
-    {
-        case QUIC_IMAGE_TYPE_RGB32:
-        case QUIC_IMAGE_TYPE_RGB24:
-            this.channels[0].correlate_row.zero = 0;
-            this.channels[1].correlate_row.zero = 0;
-            this.channels[2].correlate_row.zero = 0;
-            this.quic_rgb32_uncompress_row0(buf);
-
-            this.rows_completed++;
-            for (row = 1; row < this.height; row++)
-            {
-                var prev = buf;
-                buf = prev.subarray(stride);
-                this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0];
-                this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0];
-                this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0];
-                this.quic_rgb32_uncompress_row(prev, buf);
-                this.rows_completed++;
-            };
-            break;
-        case QUIC_IMAGE_TYPE_RGB16:
-            console.log("quic: unsupported output format\n");
-            return false;
-            break;
-        case QUIC_IMAGE_TYPE_RGBA:
-            this.channels[0].correlate_row.zero = 0;
-            this.channels[1].correlate_row.zero = 0;
-            this.channels[2].correlate_row.zero = 0;
-            this.quic_rgb32_uncompress_row0(buf);
-
-            this.channels[3].correlate_row.zero = 0;
-            this.quic_four_uncompress_row0(this.channels[3], buf);
-
-            this.rows_completed++;
-            for (row = 1; row < this.height; row++) {
-                var prev = buf;
-                buf = prev.subarray(stride);
-
-                this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0];
-                this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0];
-                this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0];
-                this.quic_rgb32_uncompress_row(prev, buf);
-
-                this.channels[3].correlate_row.zero = this.channels[3].correlate_row.row[0];
-                this.quic_four_uncompress_row(encoder.channels[3], prev, buf);
-                this.rows_completed++;
-            }
-            break;
-
-        case QUIC_IMAGE_TYPE_GRAY:
-            console.log("quic: unsupported output format\n");
-            return false;
-            break;
-
-        case QUIC_IMAGE_TYPE_INVALID:
-        default:
-            console.log("quic: bad image type\n");
-            return false;
-    }
-    return true;
-}
-
-QuicEncoder.prototype.simple_quic_decode = function(buf)
-{
-    var stride = 4; /* FIXME - proper stride calc please */
-    if (!this.quic_decode_begin(buf))
-        return undefined;
-    if (this.type != QUIC_IMAGE_TYPE_RGB32 && this.type != QUIC_IMAGE_TYPE_RGB24
-        && this.type != QUIC_IMAGE_TYPE_RGBA)
-        return undefined;
-    var out = new Uint8Array(this.width*this.height*4);
-    out[0] = 69;
-    if (this.quic_decode( out, (this.width * stride)))
-        return out;
-    return undefined;
-}
-
-function SpiceQuic()
-{
-}
-
-SpiceQuic.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        if (!encoder)
-            throw("quic: no quic encoder");
-        this.data_size = dv.getUint32(at, true);
-        at += 4;
-        var buf = new Uint8Array(mb.slice(at));
-        this.outptr = encoder.simple_quic_decode(buf);
-        if (this.outptr)
-        {
-            this.type = encoder.type;
-            this.width = encoder.width;
-            this.height = encoder.height;
-        }
-        at += buf.length;
-        return at;
-    },
-}
-
-function convert_spice_quic_to_web(context, spice_quic)
-{
-    var ret = context.createImageData(spice_quic.width, spice_quic.height);
-    var i;
-    for (i = 0; i < (ret.width * ret.height * 4); i+=4)
-    {
-        ret.data[i + 0] = spice_quic.outptr[i + 2];
-        ret.data[i + 1] = spice_quic.outptr[i + 1];
-        ret.data[i + 2] = spice_quic.outptr[i + 0];
-        if (spice_quic.type !== QUIC_IMAGE_TYPE_RGBA)
-            ret.data[i + 3] = 255;
-        else
-            ret.data[i + 3] = 255 - spice_quic.outptr[i + 3];
-    }
-   return ret;
-}
-
-/* Module initialization */
-if (need_init)
-{
-    need_init = false;
-
-    family_init(family_8bpc, 8, DEFmaxclen);
-    family_init(family_5bpc, 5, DEFmaxclen);
-    /* init_zeroLUT */
-    var i, j, k, l;
-
-    j = k = 1;
-    l = 8;
-    for (i = 0; i < 256; ++i) {
-        zeroLUT[i] = l;
-        --k;
-        if (k == 0) {
-            k = j;
-            --l;
-            j *= 2;
-        }
-    }
-
-    encoder = new QuicEncoder;
-
-    if (!encoder)
-        throw("quic: failed to create encoder");
-}
diff -pruN 0.1.7-5/README 0.2.2-0ubuntu3/README
--- 0.1.7-5/README	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/README	2019-08-06 11:45:18.000000000 +0000
@@ -5,7 +5,7 @@ Instructions and status as of August, 20
 Requirements:
 
   1.  Modern Firefox or Chrome (IE will work, but badly)
-      
+
   2.  A WebSocket proxy
 
       websockify:
@@ -24,7 +24,7 @@ Optional:
 
       With firefox, you can just open file:///your-path-to-spice.html-here
 
-      With Chrome, you have to set a secret config flag to do that, or 
+      With Chrome, you have to set a secret config flag to do that, or
       serve the files from a web server.
 
 
diff -pruN 0.1.7-5/resize.js 0.2.2-0ubuntu3/resize.js
--- 0.1.7-5/resize.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/resize.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,70 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  resize.js
-**      This bit of Javascript is a set of logic to help with window
-**  resizing, using the agent channel to request screen resizes.
-**
-**  It's a bit tricky, as we want to wait for resizing to settle down
-**  before sending a size.  Further, while horizontal resizing to use the whole
-**  browser width is fairly easy to arrange with css, resizing an element to use
-**  the whole vertical space (or to force a middle div to consume the bulk of the browser
-**  window size) is tricky, and the consensus seems to be that Javascript is
-**  the only right way to do it.
-**--------------------------------------------------------------------------*/
-function resize_helper(sc)
-{
-    var w = document.getElementById(sc.screen_id).clientWidth;
-    var h = document.getElementById(sc.screen_id).clientHeight;
-
-    var m = document.getElementById(sc.message_id);
-
-    /* Resize vertically; basically we leave a 20 pixel margin
-         at the bottom, and use the position of the message window
-         to figure out how to resize */
-    var hd = window.innerHeight - m.offsetHeight - m.offsetTop - 20;
-
-    /* Xorg requires height be a multiple of 8; round up */
-    h = h + hd;
-    if (h % 8 > 0)
-        h += (8 - (h % 8));
-
-    /* Xorg requires width be a multiple of 8; round up */
-    if (w % 8 > 0)
-        w += (8 - (w % 8));
-
-
-    sc.resize_window(0, w, h, 32, 0, 0);
-    sc.spice_resize_timer = undefined;
-}
-
-function handle_resize(e)
-{
-    var sc = window.spice_connection;
-
-    if (sc && sc.spice_resize_timer)
-    {
-        window.clearTimeout(sc.spice_resize_timer);
-        sc.spice_resize_timer = undefined;
-    }
-
-    sc.spice_resize_timer = window.setTimeout(resize_helper, 200, sc);
-}
diff -pruN 0.1.7-5/simulatecursor.js 0.2.2-0ubuntu3/simulatecursor.js
--- 0.1.7-5/simulatecursor.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/simulatecursor.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,202 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2013 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  SpiceSimulateCursor
-**      Internet Explorer 10 does not support data uri's in cursor assignment.
-**  This file provides a number of gimmicks to compensate.  First, if there
-**  is a preloaded cursor available, we will use that.  Failing that, we will
-**  simulate a cursor using an image that is moved around the screen.
-**--------------------------------------------------------------------------*/
-var SpiceSimulateCursor = {
-
-cursors : new Array(),
-unknown_cursors : new Array(),
-warned: false,
-
-add_cursor: function(sha1, value)
-{
-    SpiceSimulateCursor.cursors[sha1] = value;
-},
-
-unknown_cursor: function(sha1, curdata)
-{
-    if (! SpiceSimulateCursor.warned)
-    {
-        SpiceSimulateCursor.warned = true;
-        alert("Internet Explorer does not support dynamic cursors.  " +
-              "This page will now simulate cursors with images, " +
-              "which will be imperfect.  We recommend using Chrome or Firefox instead.  " +
-              "\n\nIf you need to use Internet Explorer, you can create a static cursor " +
-              "file for each cursor your application uses.  " +
-              "View the console log for more information on creating static cursors for your environment.");
-    }
-
-    if (! SpiceSimulateCursor.unknown_cursors[sha1])
-    {
-        SpiceSimulateCursor.unknown_cursors[sha1] = curdata;
-        console.log('Unknown cursor.  Simulation required.  To avoid simulation for this cursor, create and include a custom javascript file, and add the following line:');
-        console.log('SpiceCursorSimulator.add_cursor("' + sha1 + '"), "<your filename here>.cur");');
-        console.log('And then run following command, redirecting output into <your filename here>.cur:');
-        console.log('php -r "echo urldecode(\'' + curdata + '\');"');
-    }
-},
-
-simulate_cursor: function (spicecursor, cursor, screen, pngstr)
-{
-    var cursor_sha = hex_sha1(pngstr + ' ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y);
-    if (typeof SpiceSimulateCursor.cursors != 'undefined')
-        if (typeof SpiceSimulateCursor.cursors[cursor_sha] != 'undefined')
-        {
-            var curstr = 'url(' + SpiceSimulateCursor.cursors[cursor_sha] + '), default';
-            screen.style.cursor = curstr;
-        }
-
-    if (window.getComputedStyle(screen, null).cursor == 'auto')
-    {
-        SpiceSimulateCursor.unknown_cursor(cursor_sha, 
-            SpiceSimulateCursor.create_icondir(cursor.header.width, cursor.header.height,
-            cursor.data.byteLength, cursor.header.hot_spot_x, cursor.header.hot_spot_y) + pngstr);
-
-        document.getElementById(spicecursor.parent.screen_id).style.cursor = 'none';
-        if (! spicecursor.spice_simulated_cursor)
-        {
-            spicecursor.spice_simulated_cursor = document.createElement('img');
-
-            spicecursor.spice_simulated_cursor.style.position = 'absolute';
-            spicecursor.spice_simulated_cursor.style.display = 'none';
-            spicecursor.spice_simulated_cursor.style.overflow = 'hidden';
-
-            spicecursor.spice_simulated_cursor.spice_screen = document.getElementById(spicecursor.parent.screen_id);
-
-            spicecursor.spice_simulated_cursor.addEventListener('mousemove', SpiceSimulateCursor.handle_sim_mousemove);
-
-            spicecursor.spice_simulated_cursor.spice_screen.appendChild(spicecursor.spice_simulated_cursor);
-        }
-
-        spicecursor.spice_simulated_cursor.src = 'data:image/png,' + pngstr;
-
-        spicecursor.spice_simulated_cursor.spice_hot_x = cursor.header.hot_spot_x;
-        spicecursor.spice_simulated_cursor.spice_hot_y = cursor.header.hot_spot_y;
-
-        spicecursor.spice_simulated_cursor.style.pointerEvents = "none";
-    }
-    else
-    { 
-        if (spicecursor.spice_simulated_cursor)
-        {
-            spicecursor.spice_simulated_cursor.spice_screen.removeChild(spicecursor.spice_simulated_cursor);
-            delete spicecursor.spice_simulated_cursor;
-        }
-    }
-},
-
-handle_sim_mousemove: function(e)
-{
-    var retval;
-    var f = SpiceSimulateCursor.duplicate_mouse_event(e, this.spice_screen);
-    return this.spice_screen.dispatchEvent(f);
-},
-
-duplicate_mouse_event: function(e, target)
-{
-    var evt = document.createEvent("mouseevent");
-    evt.initMouseEvent(e.type, true, true, e.view, e.detail,
-        e.screenX, e.screenY, e.clientX, e.clientY,
-        e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
-    return evt;
-},
-
-ICONDIR: function ()
-{
-},
-
-ICONDIRENTRY: function(width, height, bytes, hot_x, hot_y)
-{
-    this.width = width;
-    this.height = height;
-    this.bytes = bytes;
-    this.hot_x = hot_x;
-    this.hot_y = hot_y;
-},
-
-
-create_icondir: function (width, height, bytes, hot_x, hot_y)
-{
-    var i;
-    var header = new SpiceSimulateCursor.ICONDIR();
-    var entry = new SpiceSimulateCursor.ICONDIRENTRY(width, height, bytes, hot_x, hot_y);
-
-    var mb = new ArrayBuffer(header.buffer_size() + entry.buffer_size());
-    var at = header.to_buffer(mb);
-    at = entry.to_buffer(mb, at);
-
-    var u8 = new Uint8Array(mb);
-    var str = "";
-    for (i = 0; i < at; i++)
-    {
-        str += "%";
-        if (u8[i] < 16)
-            str += "0";
-        str += u8[i].toString(16);
-    }
-    return str;
-},
-
-};
-
-SpiceSimulateCursor.ICONDIR.prototype = 
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint16(at, 0, true); at += 2;
-        dv.setUint16(at, 2, true); at += 2;
-        dv.setUint16(at, 1, true); at += 2;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 6;
-    }
-};
-
-SpiceSimulateCursor.ICONDIRENTRY.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint8(at, this.width); at++;
-        dv.setUint8(at, this.height); at++;
-        dv.setUint8(at, 0); at++;  /* color palette count, unused */
-        dv.setUint8(at, 0); at++;  /* reserved */
-        dv.setUint16(at, this.hot_x, true); at += 2;
-        dv.setUint16(at, this.hot_y, true); at += 2;
-        dv.setUint32(at, this.bytes, true); at += 4;
-        dv.setUint32(at, at + 4, true); at += 4;  /* Offset to bytes */
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 16;
-    }
-};
diff -pruN 0.1.7-5/spicearraybuffer.js 0.2.2-0ubuntu3/spicearraybuffer.js
--- 0.1.7-5/spicearraybuffer.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spicearraybuffer.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,58 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  SpiceArrayBufferSlice
-**    This function is a work around for IE 10, which has no slice()
-**    method in it's subclass.
-**--------------------------------------------------------------------------*/
-function SpiceArrayBufferSlice(start, end)
-{
-    start = start || 0;
-    end = end || this.byteLength;
-    if (end < 0)
-        end = this.byteLength + end;
-    if (start < 0)
-        start = this.byteLength + start;
-    if (start < 0)
-        start = 0;
-    if (end < 0)
-        end = 0;
-    if (end > this.byteLength)
-        end = this.byteLength;
-    if (start > end)
-        start = end;
-
-    var ret = new ArrayBuffer(end - start);
-    var in1 = new Uint8Array(this, start, end - start);
-    var out = new Uint8Array(ret);
-    var i;
-
-    for (i = 0; i < end - start; i++)
-        out[i] = in1[i];
-
-    return ret;
-}
-
-if (! ArrayBuffer.prototype.slice)
-{
-    ArrayBuffer.prototype.slice = SpiceArrayBufferSlice;
-    console.log("WARNING:  ArrayBuffer.slice() is missing; we are extending ArrayBuffer to compensate");
-}
diff -pruN 0.1.7-5/spice_auto.html 0.2.2-0ubuntu3/spice_auto.html
--- 0.1.7-5/spice_auto.html	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spice_auto.html	2019-08-06 11:45:18.000000000 +0000
@@ -28,37 +28,25 @@
     <head>
 
         <title>Spice Javascript client</title>
-        <script src="spicearraybuffer.js"></script> 
-        <script src="enums.js"></script>
-        <script src="atKeynames.js"></script>
-        <script src="utils.js"></script>
-        <script src="png.js"></script>
-        <script src="lz.js"></script>
-        <script src="quic.js"></script>
-        <script src="bitmap.js"></script>
-        <script src="spicedataview.js"></script>
-        <script src="spicetype.js"></script>
-        <script src="spicemsg.js"></script>
-        <script src="wire.js"></script>
-        <script src="spiceconn.js"></script>
-        <script src="display.js"></script>
-        <script src="main.js"></script>
-        <script src="inputs.js"></script>
-        <script src="webm.js"></script>
-        <script src="playback.js"></script>
-        <script src="simulatecursor.js"></script>
-        <script src="cursor.js"></script>
-        <script src="thirdparty/jsbn.js"></script>
-        <script src="thirdparty/rsa.js"></script>
-        <script src="thirdparty/prng4.js"></script>
-        <script src="thirdparty/rng.js"></script>
-        <script src="thirdparty/sha1.js"></script>
-        <script src="ticket.js"></script>
-        <script src="resize.js"></script>
-        <script src="filexfer.js"></script>
         <link rel="stylesheet" type="text/css" href="spice.css" />
 
+        <!-- ES2015/ES6 modules polyfill -->
+        <script type="module">
+            window._spice_has_module_support = true;
+        </script>
         <script>
+            window.addEventListener("load", function() {
+                if (window._spice_has_module_support) return;
+                var loader = document.createElement("script");
+                loader.src = "thirdparty/browser-es-module-loader/dist/" +
+                    "browser-es-module-loader.js";
+                document.head.appendChild(loader);
+            });
+        </script>
+
+        <script type="module" crossorigin="anonymous">
+            import * as SpiceHtml5 from './src/main.js';
+
             var host = null, port = null;
             var sc;
 
@@ -81,11 +69,15 @@
             function spice_error(e)
             {
                 disconnect();
+                if (e !== undefined && e.message === "Permission denied.") {
+                  var pass = prompt("Password");
+                  connect(pass);
+                }
             }
 
-            function connect()
+            function connect(password)
             {
-                var host, port, password, scheme = "ws://", uri;
+                var host, port, scheme = "ws://", uri;
 
                 // By default, use the host and port of server that served this file
                 host = spice_query_var('host', window.location.hostname);
@@ -109,13 +101,15 @@
 
                 // If a token variable is passed in, set the parameter in a cookie.
                 // This is used by nova-spiceproxy.
-                token = spice_query_var('token', null);
+                var token = spice_query_var('token', null);
                 if (token) {
                     spice_set_cookie('token', token, 1)
                 }
 
-                password = spice_query_var('password', '');
-                path = spice_query_var('path', 'websockify');
+                if (password === undefined) {
+                    password = spice_query_var('password', '');
+                }
+                var path = spice_query_var('path', 'websockify');
 
                 if ((!host) || (!port)) {
                     console.log("must specify host and port in URL");
@@ -134,7 +128,7 @@
 
                 try
                 {
-                    sc = new SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div",
+                    sc = new SpiceHtml5.SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div",
                                 message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected });
                 }
                 catch (e)
@@ -154,27 +148,29 @@
                 if (window.File && window.FileReader && window.FileList && window.Blob)
                 {
                     var spice_xfer_area = document.getElementById('spice-xfer-area');
-                    document.getElementById('spice-area').removeChild(spice_xfer_area);
-                    document.getElementById('spice-area').removeEventListener('dragover', handle_file_dragover, false);
-                    document.getElementById('spice-area').removeEventListener('drop', handle_file_drop, false);
+                    if (spice_xfer_area != null) {
+                      document.getElementById('spice-area').removeChild(spice_xfer_area);
+                    }
+                    document.getElementById('spice-area').removeEventListener('dragover', SpiceHtml5.handle_file_dragover, false);
+                    document.getElementById('spice-area').removeEventListener('drop', SpiceHtml5.handle_file_drop, false);
                 }
                 console.log("<< disconnect");
             }
 
             function agent_connected(sc)
             {
-                window.addEventListener('resize', handle_resize);
+                window.addEventListener('resize', SpiceHtml5.handle_resize);
                 window.spice_connection = this;
 
-                resize_helper(this);
+                SpiceHtml5.resize_helper(this);
 
                 if (window.File && window.FileReader && window.FileList && window.Blob)
                 {
                     var spice_xfer_area = document.createElement("div");
                     spice_xfer_area.setAttribute('id', 'spice-xfer-area');
                     document.getElementById('spice-area').appendChild(spice_xfer_area);
-                    document.getElementById('spice-area').addEventListener('dragover', handle_file_dragover, false);
-                    document.getElementById('spice-area').addEventListener('drop', handle_file_drop, false);
+                    document.getElementById('spice-area').addEventListener('dragover', SpiceHtml5.handle_file_dragover, false);
+                    document.getElementById('spice-area').addEventListener('drop', SpiceHtml5.handle_file_drop, false);
                 }
                 else
                 {
@@ -182,7 +178,19 @@
                 }
             }
 
-            connect();
+            /* SPICE port event listeners
+            window.addEventListener('spice-port-data', function(event) {
+                // Here we convert data to text, but really we can obtain binary data also
+                var msg_text = arraybuffer_to_str(new Uint8Array(event.detail.data));
+                DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text);
+            });
+
+            window.addEventListener('spice-port-event', function(event) {
+                DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent);
+            });
+            */
+
+            connect(undefined);
         </script>
 
     </head>
diff -pruN 0.1.7-5/spiceconn.js 0.2.2-0ubuntu3/spiceconn.js
--- 0.1.7-5/spiceconn.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spiceconn.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,492 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  SpiceConn
-**      This is the base Javascript class for establishing and
-**  managing a connection to a Spice Server.
-**  It is used to provide core functionality to the Spice main,
-**  display, inputs, and cursor channels.  See main.js for 
-**  usage.
-**--------------------------------------------------------------------------*/
-function SpiceConn(o)
-{
-    if (o === undefined || o.uri === undefined || ! o.uri)
-        throw new Error("You must specify a uri");
-
-    this.ws = new WebSocket(o.uri, 'binary');
-
-    if (! this.ws.binaryType)
-        throw new Error("WebSocket doesn't support binaryType.  Try a different browser.");
-
-    this.connection_id = o.connection_id !== undefined ? o.connection_id : 0;
-    this.type = o.type !== undefined ? o.type : SPICE_CHANNEL_MAIN;
-    this.chan_id = o.chan_id !== undefined ? o.chan_id : 0;
-    if (o.parent !== undefined)
-    {
-        this.parent = o.parent;
-        this.message_id = o.parent.message_id;
-        this.password = o.parent.password;
-    }
-    if (o.screen_id !== undefined)
-        this.screen_id = o.screen_id;
-    if (o.dump_id !== undefined)
-        this.dump_id = o.dump_id;
-    if (o.message_id !== undefined)
-        this.message_id = o.message_id;
-    if (o.password !== undefined)
-        this.password = o.password;
-    if (o.onerror !== undefined)
-        this.onerror = o.onerror;
-    if (o.onsuccess !== undefined)
-        this.onsuccess = o.onsuccess;
-    if (o.onagent !== undefined)
-        this.onagent = o.onagent;
-
-    this.state = "connecting";
-    this.ws.parent = this;
-    this.wire_reader = new SpiceWireReader(this, this.process_inbound);
-    this.messages_sent = 0;
-    this.warnings = [];
-
-    this.ws.addEventListener('open', function(e) {
-        DEBUG > 0 && console.log(">> WebSockets.onopen");
-        DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type);
-
-        /***********************************************************************
-        **          WHERE IT ALL REALLY BEGINS
-        ***********************************************************************/
-        this.parent.send_hdr();
-        this.parent.wire_reader.request(SpiceLinkHeader.prototype.buffer_size());
-        this.parent.state = "start";
-    });
-    this.ws.addEventListener('error', function(e) {
-        if ('url' in e.target) {
-            this.parent.log_err("WebSocket error: Can't connect to websocket on URL: " + e.target.url);
-        }
-        this.parent.report_error(e);
-    });
-    this.ws.addEventListener('close', function(e) {
-        DEBUG > 0 && console.log(">> WebSockets.onclose");
-        DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type);
-        DEBUG > 0 && console.log(e);
-        if (this.parent.state != "closing" && this.parent.state != "error" && this.parent.onerror !== undefined)
-        {
-            var e;
-            if (this.parent.state == "connecting")
-                e = new Error("Connection refused.");
-            else if (this.parent.state == "start" || this.parent.state == "link")
-                e = new Error("Unexpected protocol mismatch.");
-            else if (this.parent.state == "ticket")
-                e = new Error("Bad password.");
-            else
-                e = new Error("Unexpected close while " + this.parent.state);
-
-            this.parent.onerror(e);
-            this.parent.log_err(e.toString());
-        }
-    });
-
-    if (this.ws.readyState == 2 || this.ws.readyState == 3)
-        throw new Error("Unable to connect to " + o.uri);
-
-    this.timeout = window.setTimeout(spiceconn_timeout, SPICE_CONNECT_TIMEOUT, this);
-}
-
-SpiceConn.prototype =
-{
-    send_hdr : function ()
-    {
-        var hdr = new SpiceLinkHeader;
-        var msg = new SpiceLinkMess;
-
-        msg.connection_id = this.connection_id;
-        msg.channel_type = this.type;
-        // FIXME - we're not setting a channel_id...
-        msg.common_caps.push(
-            (1 << SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION) |
-            (1 << SPICE_COMMON_CAP_MINI_HEADER)
-            );
-
-        if (msg.channel_type == SPICE_CHANNEL_PLAYBACK)
-            msg.channel_caps.push(
-                (1 << SPICE_PLAYBACK_CAP_OPUS)
-            );
-        else if (msg.channel_type == SPICE_CHANNEL_MAIN)
-            msg.channel_caps.push(
-                (1 << SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)
-            );
-        else if (msg.channel_type == SPICE_CHANNEL_DISPLAY)
-            msg.channel_caps.push(
-                (1 << SPICE_DISPLAY_CAP_SIZED_STREAM) |
-                (1 << SPICE_DISPLAY_CAP_STREAM_REPORT) |
-                (1 << SPICE_DISPLAY_CAP_MULTI_CODEC) |
-                (1 << SPICE_DISPLAY_CAP_CODEC_MJPEG) |
-                (1 << SPICE_DISPLAY_CAP_CODEC_VP8)
-            );
-
-        hdr.size = msg.buffer_size();
-
-        var mb = new ArrayBuffer(hdr.buffer_size() + msg.buffer_size());
-        hdr.to_buffer(mb);
-        msg.to_buffer(mb, hdr.buffer_size());
-
-        DEBUG > 1 && console.log("Sending header:");
-        DEBUG > 2 && hexdump_buffer(mb);
-        this.ws.send(mb);
-    },
-
-    send_ticket: function(ticket)
-    {
-        var hdr = new SpiceLinkAuthTicket();
-        hdr.auth_mechanism = SPICE_COMMON_CAP_AUTH_SPICE;
-        // FIXME - we need to implement RSA to make this work right
-        hdr.encrypted_data = ticket;
-        var mb = new ArrayBuffer(hdr.buffer_size());
-
-        hdr.to_buffer(mb);
-        DEBUG > 1 && console.log("Sending ticket:");
-        DEBUG > 2 && hexdump_buffer(mb);
-        this.ws.send(mb);
-    },
-
-    send_msg: function(msg)
-    {
-        var mb = new ArrayBuffer(msg.buffer_size());
-        msg.to_buffer(mb);
-        this.messages_sent++;
-        DEBUG > 0 && console.log(">> hdr " + this.channel_type() + " type " + msg.type + " size " + mb.byteLength);
-        DEBUG > 2 && hexdump_buffer(mb);
-        this.ws.send(mb);
-    },
-
-    process_inbound: function(mb, saved_header)
-    {
-        DEBUG > 2 && console.log(this.type + ": processing message of size " + mb.byteLength + "; state is " + this.state);
-        if (this.state == "ready")
-        {
-            if (saved_header == undefined)
-            {
-                var msg = new SpiceMiniData(mb);
-
-                if (msg.type > 500)
-                {
-                    alert("Something has gone very wrong; we think we have message of type " + msg.type);
-                    debugger;
-                }
-
-                if (msg.size == 0)
-                {
-                    this.process_message(msg);
-                    this.wire_reader.request(SpiceMiniData.prototype.buffer_size());
-                }
-                else
-                {
-                    this.wire_reader.request(msg.size);
-                    this.wire_reader.save_header(msg);
-                }
-            }
-            else
-            {
-                saved_header.data = mb;
-                this.process_message(saved_header);
-                this.wire_reader.request(SpiceMiniData.prototype.buffer_size());
-                this.wire_reader.save_header(undefined);
-            }
-        }
-
-        else if (this.state == "start")
-        {
-            this.reply_hdr = new SpiceLinkHeader(mb);
-            if (this.reply_hdr.magic != SPICE_MAGIC)
-            {
-                this.state = "error";
-                var e = new Error('Error: magic mismatch: ' + this.reply_hdr.magic);
-                this.report_error(e);
-            }
-            else
-            {
-                // FIXME - Determine major/minor version requirements
-                this.wire_reader.request(this.reply_hdr.size);
-                this.state = "link";
-            }
-        }
-
-        else if (this.state == "link")
-        {
-            this.reply_link = new SpiceLinkReply(mb);
-             // FIXME - Screen the caps - require minihdr at least, right?
-            if (this.reply_link.error)
-            {
-                this.state = "error";
-                var e = new Error('Error: reply link error ' + this.reply_link.error);
-                this.report_error(e);
-            }
-            else
-            {
-                this.send_ticket(rsa_encrypt(this.reply_link.pub_key, this.password + String.fromCharCode(0)));
-                this.state = "ticket";
-                this.wire_reader.request(SpiceLinkAuthReply.prototype.buffer_size());
-            }
-        }
-
-        else if (this.state == "ticket")
-        {
-            this.auth_reply = new SpiceLinkAuthReply(mb);
-            if (this.auth_reply.auth_code == SPICE_LINK_ERR_OK)
-            {
-                DEBUG > 0 && console.log(this.type + ': Connected');
-
-                if (this.type == SPICE_CHANNEL_DISPLAY)
-                {
-                    // FIXME - pixmap and glz dictionary config info?
-                    var dinit = new SpiceMsgcDisplayInit();
-                    var reply = new SpiceMiniData();
-                    reply.build_msg(SPICE_MSGC_DISPLAY_INIT, dinit);
-                    DEBUG > 0 && console.log("Request display init");
-                    this.send_msg(reply);
-                }
-                this.state = "ready";
-                this.wire_reader.request(SpiceMiniData.prototype.buffer_size());
-                if (this.timeout)
-                {
-                    window.clearTimeout(this.timeout);
-                    delete this.timeout;
-                }
-            }
-            else
-            {
-                this.state = "error";
-                if (this.auth_reply.auth_code == SPICE_LINK_ERR_PERMISSION_DENIED)
-                {
-                    var e = new Error("Permission denied.");
-                }
-                else
-                {
-                    var e = new Error("Unexpected link error " + this.auth_reply.auth_code);
-                }
-                this.report_error(e);
-            }
-        }
-    },
-
-    process_common_messages : function(msg)
-    {
-        if (msg.type == SPICE_MSG_SET_ACK)
-        {
-            var ack = new SpiceMsgSetAck(msg.data);
-            // FIXME - what to do with generation?
-            this.ack_window = ack.window;
-            DEBUG > 1 && console.log(this.type + ": set ack to " + ack.window);
-            this.msgs_until_ack = this.ack_window;
-            var ackack = new SpiceMsgcAckSync(ack);
-            var reply = new SpiceMiniData();
-            reply.build_msg(SPICE_MSGC_ACK_SYNC, ackack);
-            this.send_msg(reply);
-            return true;
-        }
-
-        if (msg.type == SPICE_MSG_PING)
-        {
-            DEBUG > 1 && console.log("ping!");
-            var pong = new SpiceMiniData;
-            pong.type = SPICE_MSGC_PONG;
-            if (msg.data)
-            {
-                pong.data = msg.data.slice(0, 12);
-            }
-            pong.size = pong.buffer_size();
-            this.send_msg(pong);
-            return true;
-        }
-
-        if (msg.type == SPICE_MSG_NOTIFY)
-        {
-            // FIXME - Visibility + what
-            var notify = new SpiceMsgNotify(msg.data);
-            if (notify.severity == SPICE_NOTIFY_SEVERITY_ERROR)
-                this.log_err(notify.message);
-            else if (notify.severity == SPICE_NOTIFY_SEVERITY_WARN )
-                this.log_warn(notify.message);
-            else
-                this.log_info(notify.message);
-            return true;
-        }
-
-        return false;
-
-    },
-
-    process_message: function(msg)
-    {
-        var rc;
-        var start = Date.now();
-        DEBUG > 0 && console.log("<< hdr " + this.channel_type() + " type " + msg.type + " size " + (msg.data && msg.data.byteLength));
-        rc = this.process_common_messages(msg);
-        if (! rc)
-        {
-            if (this.process_channel_message)
-            {
-                rc = this.process_channel_message(msg);
-                if (! rc)
-                    this.log_warn(this.channel_type() + ": Unknown message type " + msg.type + "!");
-            }
-            else
-                this.log_err(this.channel_type() + ": No message handlers for this channel; message " + msg.type);
-        }
-
-        if (this.msgs_until_ack !== undefined && this.ack_window)
-        {
-            this.msgs_until_ack--;
-            if (this.msgs_until_ack <= 0)
-            {
-                this.msgs_until_ack = this.ack_window;
-                var ack = new SpiceMiniData();
-                ack.type = SPICE_MSGC_ACK;
-                this.send_msg(ack);
-                DEBUG > 1 && console.log(this.type + ": sent ack");
-            }
-        }
-
-        var delta = Date.now() - start;
-        if (DEBUG > 0 || delta > GAP_DETECTION_THRESHOLD)
-            console.log("delta " + this.channel_type() + ":" + msg.type + " " + delta);
-        return rc;
-    },
-
-    channel_type: function()
-    {
-        if (this.type == SPICE_CHANNEL_MAIN)
-            return "main";
-        else if (this.type == SPICE_CHANNEL_DISPLAY)
-            return "display";
-        else if (this.type == SPICE_CHANNEL_INPUTS)
-            return "inputs";
-        else if (this.type == SPICE_CHANNEL_CURSOR)
-            return "cursor";
-        else if (this.type == SPICE_CHANNEL_PLAYBACK)
-            return "playback";
-        else if (this.type == SPICE_CHANNEL_RECORD)
-            return "record";
-        else if (this.type == SPICE_CHANNEL_TUNNEL)
-            return "tunnel";
-        else if (this.type == SPICE_CHANNEL_SMARTCARD)
-            return "smartcard";
-        else if (this.type == SPICE_CHANNEL_USBREDIR)
-            return "usbredir";
-        else if (this.type == SPICE_CHANNEL_PORT)
-            return "port";
-        else if (this.type == SPICE_CHANNEL_WEBDAV)
-            return "webdav";
-        return "unknown-" + this.type;
-
-    },
-
-    log_info: function()
-    {
-        var msg = Array.prototype.join.call(arguments, " ");
-        console.log(msg);
-        if (this.message_id)
-        {
-            var p = document.createElement("p");
-            p.appendChild(document.createTextNode(msg));
-            p.className += "spice-message-info";
-            document.getElementById(this.message_id).appendChild(p);
-        }
-    },
-
-    log_warn: function()
-    {
-        var msg = Array.prototype.join.call(arguments, " ");
-        console.log("WARNING: " + msg);
-        if (this.message_id)
-        {
-            var p = document.createElement("p");
-            p.appendChild(document.createTextNode(msg));
-            p.className += "spice-message-warning";
-            document.getElementById(this.message_id).appendChild(p);
-        }
-    },
-
-    log_err: function()
-    {
-        var msg = Array.prototype.join.call(arguments, " ");
-        console.log("ERROR: " + msg);
-        if (this.message_id)
-        {
-            var p = document.createElement("p");
-            p.appendChild(document.createTextNode(msg));
-            p.className += "spice-message-error";
-            document.getElementById(this.message_id).appendChild(p);
-        }
-    },
-
-    known_unimplemented: function(type, msg)
-    {
-        if ( (!this.warnings[type]) || DEBUG > 1)
-        {
-            var str = "";
-            if (DEBUG <= 1)
-                str = " [ further notices suppressed ]";
-            this.log_warn("Unimplemented function " + type + "(" + msg + ")" + str);
-            this.warnings[type] = true;
-        }
-    },
-
-    report_error: function(e)
-    {
-        this.log_err(e.toString());
-        if (this.onerror != undefined)
-            this.onerror(e);
-        else
-            throw(e);
-    },
-
-    report_success: function(m)
-    {
-        if (this.onsuccess != undefined)
-            this.onsuccess(m);
-    },
-
-    cleanup: function()
-    {
-        if (this.timeout)
-        {
-            window.clearTimeout(this.timeout);
-            delete this.timeout;
-        }
-        if (this.ws)
-        {
-            this.ws.close();
-            this.ws = undefined;
-        }
-    },
-
-    handle_timeout: function()
-    {
-        var e = new Error("Connection timed out.");
-        this.report_error(e);
-    },
-}
-
-function spiceconn_timeout(sc)
-{
-    SpiceConn.prototype.handle_timeout.call(sc);
-}
diff -pruN 0.1.7-5/spice.css 0.2.2-0ubuntu3/spice.css
--- 0.1.7-5/spice.css	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spice.css	2019-08-06 11:45:18.000000000 +0000
@@ -36,7 +36,6 @@ body
 #login input
 {
     padding: 5px;
-    background-color: #fAfAfA;
     border: 1px inset #999999;
     outline: none;
     -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px;
@@ -104,6 +103,8 @@ body
     -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2);
     -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2);
     box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2);
+    /* We default the message box to hidden. */
+    display: none;
 }
 .spice-message p {
     margin-bottom: 0em;
@@ -115,4 +116,3 @@ body
 .spice-message-error {
     color: red;
 }
-
diff -pruN 0.1.7-5/spicedataview.js 0.2.2-0ubuntu3/spicedataview.js
--- 0.1.7-5/spicedataview.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spicedataview.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,120 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  SpiceDataView
-** FIXME FIXME 
-**    This is used because Firefox does not have DataView yet.
-**    We should use DataView if we have it, because it *has* to 
-**    be faster than this code 
-**--------------------------------------------------------------------------*/
-function SpiceDataView(buffer, byteOffset, byteLength)
-{
-    if (byteOffset !== undefined)
-    {
-        if (byteLength !== undefined)
-            this.u8 = new Uint8Array(buffer, byteOffset, byteLength);
-        else
-            this.u8 = new Uint8Array(buffer, byteOffset);
-    }
-    else
-        this.u8 = new Uint8Array(buffer);
-};
-
-SpiceDataView.prototype = {
-    getUint8:  function(byteOffset)
-    {
-        return this.u8[byteOffset];
-    },
-    getUint16:  function(byteOffset, littleEndian)
-    {
-        var low = 1, high = 0;
-        if (littleEndian)
-        {
-            low = 0;
-            high = 1;
-        }
-
-        return (this.u8[byteOffset + high] << 8) | this.u8[byteOffset + low];
-    },
-    getUint32:  function(byteOffset, littleEndian)
-    {
-        var low = 2, high = 0;
-        if (littleEndian)
-        {
-            low = 0;
-            high = 2;
-        }
-
-        return (this.getUint16(byteOffset + high, littleEndian) << 16) | 
-                this.getUint16(byteOffset + low, littleEndian);
-    },
-    getUint64: function (byteOffset, littleEndian)
-    {
-        var low = 4, high = 0;
-        if (littleEndian)
-        {
-            low = 0;
-            high = 4;
-        }
-
-        return (this.getUint32(byteOffset + high, littleEndian) << 32) |
-                this.getUint32(byteOffset + low, littleEndian);
-    },
-    setUint8:  function(byteOffset, b)
-    {
-        this.u8[byteOffset] = (b & 0xff);
-    },
-    setUint16:  function(byteOffset, i, littleEndian)
-    {
-        var low = 1, high = 0;
-        if (littleEndian)
-        {
-            low = 0;
-            high = 1;
-        }
-        this.u8[byteOffset + high] = (i & 0xffff) >> 8;
-        this.u8[byteOffset + low]  = (i & 0x00ff);
-    },
-    setUint32:  function(byteOffset, w, littleEndian)
-    {
-        var low = 2, high = 0;
-        if (littleEndian)
-        {
-            low = 0;
-            high = 2;
-        }
-
-        this.setUint16(byteOffset + high, (w & 0xffffffff) >> 16, littleEndian);
-        this.setUint16(byteOffset + low,  (w & 0x0000ffff), littleEndian);
-    },
-    setUint64:  function(byteOffset, w, littleEndian)
-    {
-        var low = 4, high = 0;
-        if (littleEndian)
-        {
-            low = 0;
-            high = 4;
-        }
-
-        this.setUint32(byteOffset + high, (w & 0xffffffffffffffff) >> 32, littleEndian);
-        this.setUint32(byteOffset + low,  (w & 0x00000000ffffffff), littleEndian);
-    },
-}
diff -pruN 0.1.7-5/spice.html 0.2.2-0ubuntu3/spice.html
--- 0.1.7-5/spice.html	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spice.html	2019-08-06 11:45:18.000000000 +0000
@@ -28,37 +28,25 @@
     <head>
 
         <title>Spice Javascript client</title>
-        <script src="spicearraybuffer.js"></script> 
-        <script src="enums.js"></script> 
-        <script src="atKeynames.js"></script> 
-        <script src="utils.js"></script> 
-        <script src="png.js"></script> 
-        <script src="lz.js"></script> 
-        <script src="quic.js"></script> 
-        <script src="bitmap.js"></script> 
-        <script src="spicedataview.js"></script> 
-        <script src="spicetype.js"></script> 
-        <script src="spicemsg.js"></script> 
-        <script src="wire.js"></script> 
-        <script src="spiceconn.js"></script> 
-        <script src="display.js"></script> 
-        <script src="main.js"></script> 
-        <script src="inputs.js"></script> 
-        <script src="webm.js"></script>
-        <script src="playback.js"></script>
-        <script src="simulatecursor.js"></script>
-        <script src="cursor.js"></script> 
-        <script src="thirdparty/jsbn.js"></script>
-        <script src="thirdparty/rsa.js"></script>
-        <script src="thirdparty/prng4.js"></script>
-        <script src="thirdparty/rng.js"></script>
-        <script src="thirdparty/sha1.js"></script>
-        <script src="ticket.js"></script>
-        <script src="resize.js"></script>
-        <script src="filexfer.js"></script>
         <link rel="stylesheet" type="text/css" href="spice.css" />
 
+        <!-- ES2015/ES6 modules polyfill -->
+        <script type="module">
+            window._spice_has_module_support = true;
+        </script>
         <script>
+            window.addEventListener("load", function() {
+                if (window._spice_has_module_support) return;
+                var loader = document.createElement("script");
+                loader.src = "thirdparty/browser-es-module-loader/dist/" +
+                    "browser-es-module-loader.js";
+                document.head.appendChild(loader);
+            });
+        </script>
+
+        <script type="module" crossorigin="anonymous">
+            import * as SpiceHtml5 from './src/main.js';
+
             var host = null, port = null;
             var sc;
 
@@ -71,8 +59,8 @@
             {
                 var host, port, password, scheme = "ws://", uri;
 
-                host = document.getElementById("host").value; 
-                port = document.getElementById("port").value; 
+                host = document.getElementById("host").value;
+                port = document.getElementById("port").value;
                 password = document.getElementById("password").value;
 
 
@@ -92,7 +80,7 @@
 
                 try
                 {
-                    sc = new SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div", 
+                    sc = new SpiceHtml5.SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div",
                                 message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected });
                 }
                 catch (e)
@@ -114,27 +102,29 @@
                 if (window.File && window.FileReader && window.FileList && window.Blob)
                 {
                     var spice_xfer_area = document.getElementById('spice-xfer-area');
-                    document.getElementById('spice-area').removeChild(spice_xfer_area);
-                    document.getElementById('spice-area').removeEventListener('dragover', handle_file_dragover, false);
-                    document.getElementById('spice-area').removeEventListener('drop', handle_file_drop, false);
+                    if (spice_xfer_area != null) {
+                      document.getElementById('spice-area').removeChild(spice_xfer_area);
+                    }
+                    document.getElementById('spice-area').removeEventListener('dragover', SpiceHtml5.handle_file_dragover, false);
+                    document.getElementById('spice-area').removeEventListener('drop', SpiceHtml5.handle_file_drop, false);
                 }
                 console.log("<< disconnect");
             }
 
             function agent_connected(sc)
             {
-                window.addEventListener('resize', handle_resize);
+                window.addEventListener('resize', SpiceHtml5.handle_resize);
                 window.spice_connection = this;
 
-                resize_helper(this);
+                SpiceHtml5.resize_helper(this);
 
                 if (window.File && window.FileReader && window.FileList && window.Blob)
                 {
                     var spice_xfer_area = document.createElement("div");
                     spice_xfer_area.setAttribute('id', 'spice-xfer-area');
                     document.getElementById('spice-area').appendChild(spice_xfer_area);
-                    document.getElementById('spice-area').addEventListener('dragover', handle_file_dragover, false);
-                    document.getElementById('spice-area').addEventListener('drop', handle_file_drop, false);
+                    document.getElementById('spice-area').addEventListener('dragover', SpiceHtml5.handle_file_dragover, false);
+                    document.getElementById('spice-area').addEventListener('drop', SpiceHtml5.handle_file_drop, false);
                 }
                 else
                 {
@@ -142,6 +132,39 @@
                 }
             }
 
+            function toggle_console()
+            {
+                var checkbox = document.getElementById('show_console');
+                var m = document.getElementById('message-div');
+
+                if (checkbox.checked)
+                {
+                    m.style.display = 'block';
+                }
+                else
+                {
+                    m.style.display = 'none';
+                }
+
+                window.addEventListener('resize', SpiceHtml5.handle_resize);
+                if (sc) {
+                    SpiceHtml5.resize_helper(sc);
+                }
+            }
+            /* SPICE port event listeners
+            window.addEventListener('spice-port-data', function(event) {
+                // Here we convert data to text, but really we can obtain binary data also
+                var msg_text = arraybuffer_to_str(new Uint8Array(event.detail.data));
+                DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text);
+            });
+
+            window.addEventListener('spice-port-event', function(event) {
+                DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent);
+            });
+            */
+
+            document.getElementById('connectButton').onclick = connect;
+            document.getElementById('show_console').onchange = toggle_console;
         </script>
 
     </head>
@@ -153,7 +176,8 @@
             <label for="host">Host:</label> <input type='text' id='host' value='localhost'> <!-- localhost -->
             <label for="port">Port:</label> <input type='text' id='port' value='5959'>
             <label for="password">Password:</label> <input type='password' id='password' value=''>
-            <button id="connectButton" onclick="connect();">Start</button>
+            <label for="show_console">Show console </label><input type="checkbox" id="show_console" value="1">
+            <button id="connectButton">Start</button>
         </div>
 
         <div id="spice-area">
diff -pruN 0.1.7-5/spicemsg.js 0.2.2-0ubuntu3/spicemsg.js
--- 0.1.7-5/spicemsg.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spicemsg.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,1280 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  Spice messages
-**      This file contains classes for passing messages to and from
-**  a spice server.  This file should arguably be generated from 
-**  spice.proto, but it was instead put together by hand.
-**--------------------------------------------------------------------------*/
-function SpiceLinkHeader(a, at)
-{
-    this.magic = SPICE_MAGIC;
-    this.major_version = SPICE_VERSION_MAJOR;
-    this.minor_version = SPICE_VERSION_MINOR;
-    this.size = 0;
-    if (a !== undefined)
-        this.from_buffer(a, at);
-}
-
-SpiceLinkHeader.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.magic = "";
-        for (var i = 0; i < 4; i++)
-            this.magic += String.fromCharCode(dv.getUint8(at + i));
-        at += 4;
-
-        this.major_version = dv.getUint32(at, true); at += 4;
-        this.minor_version = dv.getUint32(at, true); at += 4;
-        this.size = dv.getUint32(at, true); at += 4;
-    },
-
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        for (var i = 0; i < 4; i++)
-            dv.setUint8(at + i, this.magic.charCodeAt(i));
-        at += 4;
-
-        dv.setUint32(at, this.major_version, true); at += 4;
-        dv.setUint32(at, this.minor_version, true); at += 4;
-        dv.setUint32(at, this.size, true); at += 4;
-    },
-    buffer_size: function()
-    { 
-        return 16;
-    },
-}
-
-function SpiceLinkMess(a, at)
-{
-    this.connection_id = 0;
-    this.channel_type = 0;
-    this.channel_id = 0;
-    this.common_caps = [];
-    this.channel_caps = [];
-
-    if (a !== undefined)
-        this.from_buffer(a, at);
-}
-
-SpiceLinkMess.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var i;
-        var orig_at = at;
-        var dv = new SpiceDataView(a);
-        this.connection_id = dv.getUint32(at, true); at += 4;
-        this.channel_type = dv.getUint8(at, true); at++;
-        this.channel_id = dv.getUint8(at, true); at++;
-        var num_common_caps = dv.getUint32(at, true); at += 4;
-        var num_channel_caps  = dv.getUint32(at, true); at += 4;
-        var caps_offset = dv.getUint32(at, true); at += 4;
-
-        at = orig_at + caps_offset;
-        this.common_caps = [];
-        for (i = 0; i < num_common_caps; i++)
-        {
-            this.common_caps.unshift(dv.getUint32(at, true)); at += 4;
-        }
-
-        this.channel_caps = [];
-        for (i = 0; i < num_channel_caps; i++)
-        {
-            this.channel_caps.unshift(dv.getUint32(at, true)); at += 4;
-        }
-    },
-
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var orig_at = at;
-        var i;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.connection_id, true); at += 4;
-        dv.setUint8(at, this.channel_type, true); at++;
-        dv.setUint8(at, this.channel_id, true); at++;
-        dv.setUint32(at, this.common_caps.length, true); at += 4;
-        dv.setUint32(at, this.channel_caps.length, true); at += 4;
-        dv.setUint32(at, (at - orig_at) + 4, true); at += 4;
-
-        for (i = 0; i < this.common_caps.length; i++)
-        {
-            dv.setUint32(at, this.common_caps[i], true); at += 4;
-        }
-
-        for (i = 0; i < this.channel_caps.length; i++)
-        {
-            dv.setUint32(at, this.channel_caps[i], true); at += 4;
-        }
-    },
-    buffer_size: function()
-    {
-        return 18 + (4 * this.common_caps.length) + (4 * this.channel_caps.length);
-    }
-}
-
-function SpiceLinkReply(a, at)
-{
-    this.error = 0;
-    this.pub_key = undefined;
-    this.common_caps = [];
-    this.channel_caps = [];
-
-    if (a !== undefined)
-        this.from_buffer(a, at);
-}
-
-SpiceLinkReply.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var i;
-        var orig_at = at;
-        var dv = new SpiceDataView(a);
-        this.error = dv.getUint32(at, true); at += 4;
-
-        this.pub_key = create_rsa_from_mb(a, at);
-        at += SPICE_TICKET_PUBKEY_BYTES;
-
-        var num_common_caps = dv.getUint32(at, true); at += 4;
-        var num_channel_caps  = dv.getUint32(at, true); at += 4;
-        var caps_offset = dv.getUint32(at, true); at += 4;
-
-        at = orig_at + caps_offset;
-        this.common_caps = [];
-        for (i = 0; i < num_common_caps; i++)
-        {
-            this.common_caps.unshift(dv.getUint32(at, true)); at += 4;
-        }
-
-        this.channel_caps = [];
-        for (i = 0; i < num_channel_caps; i++)
-        {
-            this.channel_caps.unshift(dv.getUint32(at, true)); at += 4;
-        }
-    },
-}
-
-function SpiceLinkAuthTicket(a, at)
-{
-    this.auth_mechanism = 0;
-    this.encrypted_data = undefined;
-}
-
-SpiceLinkAuthTicket.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var i;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.auth_mechanism, true); at += 4;
-        for (i = 0; i < SPICE_TICKET_KEY_PAIR_LENGTH / 8; i++)
-        {
-            if (this.encrypted_data && i < this.encrypted_data.length)
-                dv.setUint8(at, this.encrypted_data[i], true);
-            else
-                dv.setUint8(at, 0, true);
-            at++;
-        }
-    },
-    buffer_size: function()
-    {
-        return 4 + (SPICE_TICKET_KEY_PAIR_LENGTH / 8);
-    }
-}
-
-function SpiceLinkAuthReply(a, at)
-{
-    this.auth_code = 0;
-    if (a !== undefined)
-        this.from_buffer(a, at);
-}
-
-SpiceLinkAuthReply.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.auth_code = dv.getUint32(at, true); at += 4;
-    },
-    buffer_size: function()
-    {
-        return 4;
-    }
-}
-
-function SpiceMiniData(a, at)
-{
-    this.type = 0;
-    this.size = 0;
-    this.data = undefined;
-    if (a !== undefined)
-        this.from_buffer(a, at);
-}
-
-SpiceMiniData.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var i;
-        var dv = new SpiceDataView(a);
-        this.type = dv.getUint16(at, true); at += 2;
-        this.size = dv.getUint32(at, true); at += 4;
-        if (a.byteLength > at)
-        {
-            this.data = a.slice(at);
-            at += this.data.byteLength;
-        }
-    },
-    to_buffer : function(a, at)
-    {
-        at = at || 0;
-        var i;
-        var dv = new SpiceDataView(a);
-        dv.setUint16(at, this.type, true); at += 2;
-        dv.setUint32(at, this.data ? this.data.byteLength : 0, true); at += 4;
-        if (this.data && this.data.byteLength > 0)
-        {
-            var u8arr = new Uint8Array(this.data);
-            for (i = 0; i < u8arr.length; i++, at++)
-                dv.setUint8(at, u8arr[i], true);
-        }
-    },
-    build_msg : function(in_type,  extra)
-    {
-        this.type = in_type;
-        this.size = extra.buffer_size();
-        this.data = new ArrayBuffer(this.size);
-        extra.to_buffer(this.data);
-    },
-    buffer_size: function()
-    {
-        if (this.data)
-            return 6 + this.data.byteLength;
-        else
-            return 6;
-    },
-}
-
-function SpiceMsgChannels(a, at)
-{
-    this.num_of_channels = 0;
-    this.channels = [];
-    if (a !== undefined)
-        this.from_buffer(a, at);
-}
-
-SpiceMsgChannels.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var i;
-        var dv = new SpiceDataView(a);
-        this.num_of_channels = dv.getUint32(at, true); at += 4;
-        for (i = 0; i < this.num_of_channels; i++)
-        {
-            var chan = new SpiceChannelId();
-            at = chan.from_dv(dv, at, a);
-            this.channels.push(chan);
-        }
-    },
-}
-
-function SpiceMsgMainInit(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgMainInit.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.session_id = dv.getUint32(at, true); at += 4;
-        this.display_channels_hint = dv.getUint32(at, true); at += 4;
-        this.supported_mouse_modes = dv.getUint32(at, true); at += 4;
-        this.current_mouse_mode = dv.getUint32(at, true); at += 4;
-        this.agent_connected = dv.getUint32(at, true); at += 4;
-        this.agent_tokens = dv.getUint32(at, true); at += 4;
-        this.multi_media_time = dv.getUint32(at, true); at += 4;
-        this.ram_hint = dv.getUint32(at, true); at += 4;
-    },
-}
-
-function SpiceMsgMainMouseMode(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgMainMouseMode.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.supported_modes = dv.getUint16(at, true); at += 2;
-        this.current_mode = dv.getUint16(at, true); at += 2;
-    },
-}
-
-function SpiceMsgMainAgentData(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgMainAgentData.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.protocol = dv.getUint32(at, true); at += 4;
-        this.type = dv.getUint32(at, true); at += 4;
-        this.opaque = dv.getUint64(at, true); at += 8;
-        this.size = dv.getUint32(at, true); at += 4;
-        if (a.byteLength > at)
-        {
-            this.data = a.slice(at);
-            at += this.data.byteLength;
-        }
-    }
-}
-
-function SpiceMsgMainAgentTokens(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgMainAgentTokens.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.num_tokens = dv.getUint32(at, true); at += 4;
-    },
-}
-
-function SpiceMsgSetAck(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgSetAck.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.generation = dv.getUint32(at, true); at += 4;
-        this.window = dv.getUint32(at, true); at += 4;
-    },
-}
-
-function SpiceMsgcAckSync(ack)
-{
-    this.generation = ack.generation;
-}
-
-SpiceMsgcAckSync.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.generation, true); at += 4;
-    },
-    buffer_size: function()
-    {
-        return 4;
-    }
-}
-
-function SpiceMsgcMainMouseModeRequest(mode)
-{
-    this.mode = mode;
-}
-
-SpiceMsgcMainMouseModeRequest.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint16(at, this.mode, true); at += 2;
-    },
-    buffer_size: function()
-    {
-        return 2;
-    }
-}
-
-function SpiceMsgcMainAgentStart(num_tokens)
-{
-    this.num_tokens = num_tokens;
-}
-
-SpiceMsgcMainAgentStart.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.num_tokens, true); at += 4;
-    },
-    buffer_size: function()
-    {
-        return 4;
-    }
-}
-
-function SpiceMsgcMainAgentData(type, data)
-{
-    this.protocol = VD_AGENT_PROTOCOL;
-    this.type = type;
-    this.opaque = 0;
-    this.size = data.buffer_size();
-    this.data = data;
-}
-
-SpiceMsgcMainAgentData.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.protocol, true); at += 4;
-        dv.setUint32(at, this.type, true); at += 4;
-        dv.setUint64(at, this.opaque, true); at += 8;
-        dv.setUint32(at, this.size, true); at += 4;
-        this.data.to_buffer(a, at);
-    },
-    buffer_size: function()
-    {
-        return 4 + 4 + 8 + 4 + this.data.buffer_size();
-    }
-}
-
-function VDAgentAnnounceCapabilities(request, caps)
-{
-    if (caps)
-    {
-        this.request = request;
-        this.caps = caps;
-    }
-    else
-        this.from_buffer(request);
-}
-
-VDAgentAnnounceCapabilities.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.request, true); at += 4;
-        dv.setUint32(at, this.caps, true); at += 4;
-    },
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.request = dv.getUint32(at, true); at += 4;
-        this.caps = dv.getUint32(at, true); at += 4;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 8;
-    }
-}
-
-function VDAgentMonitorsConfig(flags, width, height, depth, x, y)
-{
-    this.num_mon = 1;
-    this.flags = flags;
-    this.width = width;
-    this.height = height;
-    this.depth = depth;
-    this.x = x;
-    this.y = y;
-}
-
-VDAgentMonitorsConfig.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.num_mon, true); at += 4;
-        dv.setUint32(at, this.flags, true); at += 4;
-        dv.setUint32(at, this.height, true); at += 4;
-        dv.setUint32(at, this.width, true); at += 4;
-        dv.setUint32(at, this.depth, true); at += 4;
-        dv.setUint32(at, this.x, true); at += 4;
-        dv.setUint32(at, this.y, true); at += 4;
-    },
-    buffer_size: function()
-    {
-        return 28;
-    }
-}
-
-function VDAgentFileXferStatusMessage(data, result)
-{
-    if (result)
-    {
-        this.id = data;
-        this.result = result;
-    }
-    else
-        this.from_buffer(data);
-}
-
-VDAgentFileXferStatusMessage.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.id, true); at += 4;
-        dv.setUint32(at, this.result, true); at += 4;
-    },
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.id = dv.getUint32(at, true); at += 4;
-        this.result = dv.getUint32(at, true); at += 4;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 8;
-    }
-}
-
-function VDAgentFileXferStartMessage(id, name, size)
-{
-    this.id = id;
-    this.string = "[vdagent-file-xfer]\n"+"name="+name+"\nsize="+size+"\n";
-}
-
-VDAgentFileXferStartMessage.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.id, true); at += 4;
-        for (var i = 0; i < this.string.length; i++, at++)
-            dv.setUint8(at, this.string.charCodeAt(i));
-    },
-    buffer_size: function()
-    {
-        return 4 + this.string.length + 1;
-    }
-}
-
-function VDAgentFileXferDataMessage(id, size, data)
-{
-    this.id = id;
-    this.size = size;
-    this.data = data;
-}
-
-VDAgentFileXferDataMessage.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.id, true); at += 4;
-        dv.setUint64(at, this.size, true); at += 8;
-        if (this.data && this.data.byteLength > 0)
-        {
-            var u8arr = new Uint8Array(this.data);
-            for (var i = 0; i < u8arr.length; i++, at++)
-                dv.setUint8(at, u8arr[i]);
-        }
-    },
-    buffer_size: function()
-    {
-        return 12 + this.size;
-    }
-}
-
-function SpiceMsgNotify(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgNotify.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var i;
-        var dv = new SpiceDataView(a);
-        this.time_stamp = dv.getUint64(at, true); at += 8;
-        this.severity = dv.getUint32(at, true); at += 4;
-        this.visibility = dv.getUint32(at, true); at += 4;
-        this.what = dv.getUint32(at, true); at += 4;
-        this.message_len = dv.getUint32(at, true); at += 4;
-        this.message = "";
-        for (i = 0; i < this.message_len; i++)
-        {
-            var c = dv.getUint8(at, true); at++;
-            this.message += String.fromCharCode(c);
-        }
-    },
-}
-
-function SpiceMsgcDisplayInit()
-{
-    this.pixmap_cache_id = 1;
-    this.glz_dictionary_id = 0;
-    this.pixmap_cache_size = 10 * 1024 * 1024;
-    this.glz_dictionary_window_size = 0;
-}
-
-SpiceMsgcDisplayInit.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint8(at, this.pixmap_cache_id, true); at++;
-        dv.setUint64(at, this.pixmap_cache_size, true); at += 8;
-        dv.setUint8(at, this.glz_dictionary_id, true); at++;
-        dv.setUint32(at, this.glz_dictionary_window_size, true); at += 4;
-    },
-    buffer_size: function()
-    {
-        return 14;
-    }
-}
-
-function SpiceMsgDisplayBase()
-{
-}
-
-SpiceMsgDisplayBase.prototype =
-{
-    from_dv : function(dv, at, mb)
-    {
-        this.surface_id = dv.getUint32(at, true); at += 4;
-        this.box = new SpiceRect;
-        at = this.box.from_dv(dv, at, mb);
-        this.clip = new SpiceClip;
-        return this.clip.from_dv(dv, at, mb);
-    },
-}
-
-function SpiceMsgDisplayDrawCopy(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayDrawCopy.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.base = new SpiceMsgDisplayBase;
-        at = this.base.from_dv(dv, at, a);
-        this.data = new SpiceCopy;
-        return this.data.from_dv(dv, at, a);
-    },
-}
-
-function SpiceMsgDisplayDrawFill(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayDrawFill.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.base = new SpiceMsgDisplayBase;
-        at = this.base.from_dv(dv, at, a);
-        this.data = new SpiceFill;
-        return this.data.from_dv(dv, at, a);
-    },
-}
-
-function SpiceMsgDisplayCopyBits(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayCopyBits.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.base = new SpiceMsgDisplayBase;
-        at = this.base.from_dv(dv, at, a);
-        this.src_pos = new SpicePoint;
-        return this.src_pos.from_dv(dv, at, a);
-    },
-}
-
-
-function SpiceMsgSurfaceCreate(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgSurfaceCreate.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.surface = new SpiceSurface;
-        return this.surface.from_dv(dv, at, a);
-    },
-}
-
-function SpiceMsgSurfaceDestroy(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgSurfaceDestroy.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.surface_id = dv.getUint32(at, true); at += 4;
-    },
-}
-
-function SpiceMsgInputsInit(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgInputsInit.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.keyboard_modifiers = dv.getUint16(at, true); at += 2;
-        return at;
-    },
-}
-
-function SpiceMsgInputsKeyModifiers(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgInputsKeyModifiers.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.keyboard_modifiers = dv.getUint16(at, true); at += 2;
-        return at;
-    },
-}
-
-function SpiceMsgCursorInit(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgCursorInit.prototype =
-{
-    from_buffer: function(a, at, mb)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.position = new SpicePoint16;
-        at = this.position.from_dv(dv, at, mb);
-        this.trail_length = dv.getUint16(at, true); at += 2;
-        this.trail_frequency = dv.getUint16(at, true); at += 2;
-        this.visible = dv.getUint8(at, true); at ++;
-        this.cursor = new SpiceCursor;
-        return this.cursor.from_dv(dv, at, a);
-    },
-}
-
-function SpiceMsgPlaybackData(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgPlaybackData.prototype =
-{
-    from_buffer: function(a, at, mb)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.time = dv.getUint32(at, true); at += 4;
-        if (a.byteLength > at)
-        {
-            this.data = a.slice(at);
-            at += this.data.byteLength;
-        }
-        return at;
-    },
-}
-
-function SpiceMsgPlaybackMode(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgPlaybackMode.prototype =
-{
-    from_buffer: function(a, at, mb)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.time = dv.getUint32(at, true); at += 4;
-        this.mode = dv.getUint16(at, true); at += 2;
-        if (a.byteLength > at)
-        {
-            this.data = a.slice(at);
-            at += this.data.byteLength;
-        }
-        return at;
-    },
-}
-
-function SpiceMsgPlaybackStart(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgPlaybackStart.prototype =
-{
-    from_buffer: function(a, at, mb)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.channels = dv.getUint32(at, true); at += 4;
-        this.format = dv.getUint16(at, true); at += 2;
-        this.frequency = dv.getUint32(at, true); at += 4;
-        this.time = dv.getUint32(at, true); at += 4;
-        return at;
-    },
-}
-
-
-
-function SpiceMsgCursorSet(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgCursorSet.prototype =
-{
-    from_buffer: function(a, at, mb)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.position = new SpicePoint16;
-        at = this.position.from_dv(dv, at, mb);
-        this.visible = dv.getUint8(at, true); at ++;
-        this.cursor = new SpiceCursor;
-        return this.cursor.from_dv(dv, at, a);
-    },
-}
-
-
-function SpiceMsgcMousePosition(sc, e)
-{
-    // FIXME - figure out how to correctly compute display_id
-    this.display_id = 0;
-    this.buttons_state = sc.buttons_state;
-    if (e)
-    {
-        var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
-        var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
-
-        this.x = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft + scrollLeft;
-        this.y = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop + scrollTop;
-        sc.mousex = this.x;
-        sc.mousey = this.y; 
-    }
-    else
-    {
-        this.x = this.y = this.buttons_state = 0;
-    }
-}
-
-SpiceMsgcMousePosition.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.x, true); at += 4;
-        dv.setUint32(at, this.y, true); at += 4;
-        dv.setUint16(at, this.buttons_state, true); at += 2;
-        dv.setUint8(at, this.display_id, true); at += 1;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 11;
-    }
-}
-
-function SpiceMsgcMouseMotion(sc, e)
-{
-    // FIXME - figure out how to correctly compute display_id
-    this.display_id = 0;
-    this.buttons_state = sc.buttons_state;
-    if (e)
-    {
-        this.x = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft;
-        this.y = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop;
-
-        if (sc.mousex !== undefined)
-        {
-            this.x -= sc.mousex;
-            this.y -= sc.mousey;
-        }
-        sc.mousex = e.clientX - sc.display.surfaces[sc.display.primary_surface].canvas.offsetLeft;
-        sc.mousey = e.clientY - sc.display.surfaces[sc.display.primary_surface].canvas.offsetTop;
-    }
-    else
-    {
-        this.x = this.y = this.buttons_state = 0;
-    }
-}
-
-/* Use the same functions as for MousePosition */
-SpiceMsgcMouseMotion.prototype.to_buffer = SpiceMsgcMousePosition.prototype.to_buffer;
-SpiceMsgcMouseMotion.prototype.buffer_size = SpiceMsgcMousePosition.prototype.buffer_size;
-
-function SpiceMsgcMousePress(sc, e)
-{
-    if (e)
-    {
-        this.button = e.button + 1;
-        this.buttons_state = 1 << e.button;
-        sc.buttons_state = this.buttons_state;
-    }
-    else
-    {
-        this.button = SPICE_MOUSE_BUTTON_LEFT;
-        this.buttons_state = SPICE_MOUSE_BUTTON_MASK_LEFT;
-    }
-}
-
-SpiceMsgcMousePress.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint8(at, this.button, true); at ++;
-        dv.setUint16(at, this.buttons_state, true); at += 2;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 3;
-    }
-}
-
-function SpiceMsgcMouseRelease(sc, e)
-{
-    if (e)
-    {
-        this.button = e.button + 1;
-        this.buttons_state = 0;
-        sc.buttons_state = this.buttons_state;
-    }
-    else
-    {
-        this.button = SPICE_MOUSE_BUTTON_LEFT;
-        this.buttons_state = 0;
-    }
-}
-
-/* Use the same functions as for MousePress */
-SpiceMsgcMouseRelease.prototype.to_buffer = SpiceMsgcMousePress.prototype.to_buffer;
-SpiceMsgcMouseRelease.prototype.buffer_size = SpiceMsgcMousePress.prototype.buffer_size;
-
-
-function SpiceMsgcKeyDown(e)
-{
-    if (e)
-    {
-        this.code = keycode_to_start_scan(e.keyCode);
-    }
-    else
-    {
-        this.code = 0;
-    }
-}
-
-SpiceMsgcKeyDown.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.code, true); at += 4;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 4;
-    }
-}
-
-function SpiceMsgcKeyUp(e)
-{
-    if (e)
-    {
-        this.code = keycode_to_end_scan(e.keyCode);
-    }
-    else
-    {
-        this.code = 0;
-    }
-}
-
-/* Use the same functions as for KeyDown */
-SpiceMsgcKeyUp.prototype.to_buffer = SpiceMsgcKeyDown.prototype.to_buffer;
-SpiceMsgcKeyUp.prototype.buffer_size = SpiceMsgcKeyDown.prototype.buffer_size;
-
-function SpiceMsgDisplayStreamCreate(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayStreamCreate.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.surface_id = dv.getUint32(at, true); at += 4;
-        this.id = dv.getUint32(at, true); at += 4;
-        this.flags = dv.getUint8(at, true); at += 1;
-        this.codec_type = dv.getUint8(at, true); at += 1;
-        this.stamp = dv.getUint64(at, true); at += 8;
-        this.stream_width = dv.getUint32(at, true); at += 4;
-        this.stream_height = dv.getUint32(at, true); at += 4;
-        this.src_width = dv.getUint32(at, true); at += 4;
-        this.src_height = dv.getUint32(at, true); at += 4;
-
-        this.dest = new SpiceRect;
-        at = this.dest.from_dv(dv, at, a);
-        this.clip = new SpiceClip;
-        this.clip.from_dv(dv, at, a);
-    },
-}
-
-function SpiceStreamDataHeader(a, at)
-{
-}
-
-SpiceStreamDataHeader.prototype =
-{
-    from_dv : function(dv, at, mb)
-    {
-        this.id = dv.getUint32(at, true); at += 4;
-        this.multi_media_time = dv.getUint32(at, true); at += 4;
-        return at;
-    },
-}
-
-function SpiceMsgDisplayStreamData(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayStreamData.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.base = new SpiceStreamDataHeader;
-        at = this.base.from_dv(dv, at, a);
-        this.data_size = dv.getUint32(at, true); at += 4;
-        this.data = dv.u8.subarray(at, at + this.data_size);
-    },
-}
-
-function SpiceMsgDisplayStreamDataSized(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayStreamDataSized.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.base = new SpiceStreamDataHeader;
-        at = this.base.from_dv(dv, at, a);
-        this.width = dv.getUint32(at, true); at += 4;
-        this.height = dv.getUint32(at, true); at += 4;
-        this.dest = new SpiceRect;
-        at = this.dest.from_dv(dv, at, a);
-        this.data_size = dv.getUint32(at, true); at += 4;
-        this.data = dv.u8.subarray(at, at + this.data_size);
-    },
-}
-
-
-function SpiceMsgDisplayStreamClip(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayStreamClip.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.id = dv.getUint32(at, true); at += 4;
-        this.clip = new SpiceClip;
-        this.clip.from_dv(dv, at, a);
-    },
-}
-
-function SpiceMsgDisplayStreamDestroy(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayStreamDestroy.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.id = dv.getUint32(at, true); at += 4;
-    },
-}
-
-function SpiceMsgDisplayStreamActivateReport(a, at)
-{
-    this.from_buffer(a, at);
-}
-
-SpiceMsgDisplayStreamActivateReport.prototype =
-{
-    from_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.stream_id = dv.getUint32(at, true); at += 4;
-        this.unique_id = dv.getUint32(at, true); at += 4;
-        this.max_window_size = dv.getUint32(at, true); at += 4;
-        this.timeout_ms = dv.getUint32(at, true); at += 4;
-    },
-}
-
-function SpiceMsgcDisplayStreamReport(stream_id, unique_id)
-{
-    this.stream_id = stream_id;
-    this.unique_id = unique_id;
-    this.start_frame_mm_time = 0;
-    this.end_frame_mm_time = 0;
-    this.num_frames = 0;
-    this.num_drops = 0;
-    this.last_frame_delay = 0;
-
-    // TODO - Implement audio delay
-    this.audio_delay = -1;
-}
-
-SpiceMsgcDisplayStreamReport.prototype =
-{
-    to_buffer: function(a, at)
-    {
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        dv.setUint32(at, this.stream_id, true); at += 4;
-        dv.setUint32(at, this.unique_id, true); at += 4;
-        dv.setUint32(at, this.start_frame_mm_time, true); at += 4;
-        dv.setUint32(at, this.end_frame_mm_time, true); at += 4;
-        dv.setUint32(at, this.num_frames, true); at += 4;
-        dv.setUint32(at, this.num_drops, true); at += 4;
-        dv.setUint32(at, this.last_frame_delay, true); at += 4;
-        dv.setUint32(at, this.audio_delay, true); at += 4;
-        return at;
-    },
-    buffer_size: function()
-    {
-        return 8 * 4;
-    }
-}
-
-function SpiceMsgDisplayInvalList(a, at)
-{
-    this.count = 0;
-    this.resources = [];
-    this.from_buffer(a,at);
-}
-
-SpiceMsgDisplayInvalList.prototype =
-{
-    from_buffer: function (a, at)
-    {
-        var i;
-        at = at || 0;
-        var dv = new SpiceDataView(a);
-        this.count = dv.getUint16(at, true); at += 2;
-        for (i = 0; i < this.count; i++)
-        {
-            this.resources[i] = {};
-            this.resources[i].type = dv.getUint8(at, true); at++;
-            this.resources[i].id = dv.getUint64(at, true); at += 8;
-        }
-    },
-}
diff -pruN 0.1.7-5/spicetype.js 0.2.2-0ubuntu3/spicetype.js
--- 0.1.7-5/spicetype.js	2016-08-17 19:44:46.000000000 +0000
+++ 0.2.2-0ubuntu3/spicetype.js	1970-01-01 00:00:00.000000000 +0000
@@ -1,473 +0,0 @@
-"use strict";
-/*
-   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
-
-   This file is part of spice-html5.
-
-   spice-html5 is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   spice-html5 is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*----------------------------------------------------------------------------
-**  Spice types
-**      This file contains classes for common spice types.
-**  Generally, they are used as helpers in reading and writing messages
-**  to and from the server.
-**--------------------------------------------------------------------------*/
-
-function SpiceChannelId()
-{
-}
-SpiceChannelId.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.type = dv.getUint8(at, true); at ++;
-        this.id = dv.getUint8(at, true); at ++;
-        return at;
-    },
-}
-
-function SpiceRect()
-{
-}
-
-SpiceRect.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.top = dv.getUint32(at, true); at += 4;
-        this.left = dv.getUint32(at, true); at += 4;
-        this.bottom = dv.getUint32(at, true); at += 4;
-        this.right = dv.getUint32(at, true); at += 4;
-        return at;
-    },
-    is_same_size : function(r)
-    {
-        if ((this.bottom - this.top) == (r.bottom - r.top) &&
-            (this.right - this.left) == (r.right - r.left) )
-            return true;
-
-        return false;
-    },
-}
-
-function SpiceClipRects()
-{
-}
-
-SpiceClipRects.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        var i;
-        this.num_rects = dv.getUint32(at, true); at += 4;
-        if (this.num_rects > 0)
-            this.rects = [];
-        for (i = 0; i < this.num_rects; i++)
-        {
-            this.rects[i] = new SpiceRect();
-            at = this.rects[i].from_dv(dv, at, mb);
-        }
-        return at;
-    },
-}
-
-function SpiceClip()
-{
-}
-
-SpiceClip.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.type = dv.getUint8(at, true); at ++;
-        if (this.type == SPICE_CLIP_TYPE_RECTS)
-        {
-            this.rects = new SpiceClipRects();
-            at = this.rects.from_dv(dv, at, mb);
-        }
-        return at;
-    },
-}
-
-function SpiceImageDescriptor()
-{
-}
-
-SpiceImageDescriptor.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.id = dv.getUint64(at, true); at += 8;
-        this.type  = dv.getUint8(at, true); at ++;
-        this.flags = dv.getUint8(at, true); at ++;
-        this.width = dv.getUint32(at, true); at += 4;
-        this.height= dv.getUint32(at, true); at += 4;
-        return at;
-    },
-}
-
-function SpicePalette()
-{
-}
-
-SpicePalette.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        var i;
-        this.unique = dv.getUint64(at, true); at += 8;
-        this.num_ents = dv.getUint16(at, true); at += 2;
-        this.ents = [];
-        for (i = 0; i < this.num_ents; i++)
-        {
-            this.ents[i] = dv.getUint32(at, true); at += 4;
-        }
-        return at;
-    },
-}
-
-function SpiceBitmap()
-{
-}
-
-SpiceBitmap.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.format = dv.getUint8(at, true); at++;
-        this.flags  = dv.getUint8(at, true); at++;
-        this.x = dv.getUint32(at, true); at += 4;
-        this.y = dv.getUint32(at, true); at += 4;
-        this.stride = dv.getUint32(at, true); at += 4;
-        if (this.flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE)
-        {
-            this.palette_id = dv.getUint64(at, true); at += 8;
-        }
-        else
-        {
-            var offset = dv.getUint32(at, true); at += 4;
-            if (offset == 0)
-                this.palette = null;
-            else
-            {
-                this.palette = new SpicePalette;
-                this.palette.from_dv(dv, offset, mb);
-            }
-        }
-        // FIXME - should probably constrain this to the offset
-        //          of palette, if non zero
-        this.data   = mb.slice(at);
-        at += this.data.byteLength;
-        return at;
-    },
-}
-
-function SpiceImage()
-{
-}
-
-SpiceImage.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.descriptor = new SpiceImageDescriptor;
-        at = this.descriptor.from_dv(dv, at, mb);
-
-        if (this.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB)
-        {
-            this.lz_rgb = new Object();
-            this.lz_rgb.length = dv.getUint32(at, true); at += 4;
-            var initial_at = at;
-            this.lz_rgb.magic = "";
-            for (var i = 3; i >= 0; i--)
-                this.lz_rgb.magic += String.fromCharCode(dv.getUint8(at + i));
-            at += 4;
-
-            // NOTE:  The endian change is *correct*
-            this.lz_rgb.version = dv.getUint32(at); at += 4;
-            this.lz_rgb.type = dv.getUint32(at); at += 4;
-            this.lz_rgb.width = dv.getUint32(at); at += 4;
-            this.lz_rgb.height = dv.getUint32(at); at += 4;
-            this.lz_rgb.stride = dv.getUint32(at); at += 4;
-            this.lz_rgb.top_down = dv.getUint32(at); at += 4;
-
-            var header_size = at - initial_at;
-
-            this.lz_rgb.data   = mb.slice(at, this.lz_rgb.length + at - header_size);
-            at += this.lz_rgb.data.byteLength;
-
-        }
-
-        if (this.descriptor.type == SPICE_IMAGE_TYPE_BITMAP)
-        {
-            this.bitmap = new SpiceBitmap;
-            at = this.bitmap.from_dv(dv, at, mb);
-        }
-
-        if (this.descriptor.type == SPICE_IMAGE_TYPE_SURFACE)
-        {
-            this.surface_id = dv.getUint32(at, true); at += 4;
-        }
-
-        if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG)
-        {
-            this.jpeg = new Object;
-            this.jpeg.data_size = dv.getUint32(at, true); at += 4;
-            this.jpeg.data = mb.slice(at);
-            at += this.jpeg.data.byteLength;
-        }
-
-        if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA)
-        {
-            this.jpeg_alpha = new Object;
-            this.jpeg_alpha.flags = dv.getUint8(at, true); at += 1;
-            this.jpeg_alpha.jpeg_size = dv.getUint32(at, true); at += 4;
-            this.jpeg_alpha.data_size = dv.getUint32(at, true); at += 4;
-            this.jpeg_alpha.data = mb.slice(at, this.jpeg_alpha.jpeg_size + at);
-            at += this.jpeg_alpha.data.byteLength;
-            // Alpha channel is an LZ image
-            this.jpeg_alpha.alpha = new Object();
-            this.jpeg_alpha.alpha.length = this.jpeg_alpha.data_size - this.jpeg_alpha.jpeg_size;
-            var initial_at = at;
-            this.jpeg_alpha.alpha.magic = "";
-            for (var i = 3; i >= 0; i--)
-                this.jpeg_alpha.alpha.magic += String.fromCharCode(dv.getUint8(at + i));
-            at += 4;
-
-            // NOTE:  The endian change is *correct*
-            this.jpeg_alpha.alpha.version = dv.getUint32(at); at += 4;
-            this.jpeg_alpha.alpha.type = dv.getUint32(at); at += 4;
-            this.jpeg_alpha.alpha.width = dv.getUint32(at); at += 4;
-            this.jpeg_alpha.alpha.height = dv.getUint32(at); at += 4;
-            this.jpeg_alpha.alpha.stride = dv.getUint32(at); at += 4;
-            this.jpeg_alpha.alpha.top_down = dv.getUint32(at); at += 4;
-
-            var header_size = at - initial_at;
-
-            this.jpeg_alpha.alpha.data   = mb.slice(at, this.jpeg_alpha.alpha.length + at - header_size);
-            at += this.jpeg_alpha.alpha.data.byteLength;
-        }
-
-        if (this.descriptor.type == SPICE_IMAGE_TYPE_QUIC)
-        {
-            this.quic = new SpiceQuic;
-            at = this.quic.from_dv(dv, at, mb);
-        }
-        return at;
-    },
-}
-
-
-function SpiceQMask()
-{
-}
-
-SpiceQMask.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.flags  = dv.getUint8(at, true); at++;
-        this.pos = new SpicePoint;
-        at = this.pos.from_dv(dv, at, mb);
-        var offset = dv.getUint32(at, true); at += 4;
-        if (offset == 0)
-        {
-            this.bitmap = null;
-            return at;
-        }
-
-        this.bitmap = new SpiceImage;
-        return this.bitmap.from_dv(dv, offset, mb);
-    },
-}
-
-
-function SpicePattern()
-{
-}
-
-SpicePattern.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        var offset = dv.getUint32(at, true); at += 4;
-        if (offset == 0)
-        {
-            this.pat = null;
-        }
-        else
-        {
-            this.pat = new SpiceImage;
-            this.pat.from_dv(dv, offset, mb);
-        }
-
-        this.pos = new SpicePoint;
-        return this.pos.from_dv(dv, at, mb);
-    }
-}
-
-function SpiceBrush()
-{
-}
-
-SpiceBrush.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.type = dv.getUint8(at, true); at ++;
-        if (this.type == SPICE_BRUSH_TYPE_SOLID)
-        {
-            this.color = dv.getUint32(at, true); at += 4;
-        }
-        else if (this.type == SPICE_BRUSH_TYPE_PATTERN)
-        {
-            this.pattern = new SpicePattern;
-            at = this.pattern.from_dv(dv, at, mb);
-        }
-        return at;
-    },
-}
-
-function SpiceFill()
-{
-}
-
-SpiceFill.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.brush = new SpiceBrush;
-        at = this.brush.from_dv(dv, at, mb);
-        this.rop_descriptor = dv.getUint16(at, true); at += 2;
-        this.mask = new SpiceQMask;
-        return this.mask.from_dv(dv, at, mb);
-    },
-}
-
-
-function SpiceCopy()
-{
-}
-
-SpiceCopy.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        var offset = dv.getUint32(at, true); at += 4;
-        if (offset == 0)
-        {
-            this.src_bitmap = null;
-        }
-        else
-        {
-            this.src_bitmap = new SpiceImage;
-            this.src_bitmap.from_dv(dv, offset, mb);
-        }
-        this.src_area = new SpiceRect;
-        at = this.src_area.from_dv(dv, at, mb);
-        this.rop_descriptor = dv.getUint16(at, true); at += 2;
-        this.scale_mode = dv.getUint8(at, true); at ++;
-        this.mask = new SpiceQMask;
-        return this.mask.from_dv(dv, at, mb);
-    },
-}
-
-function SpicePoint16()
-{
-}
-
-SpicePoint16.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.x = dv.getUint16(at, true); at += 2;
-        this.y = dv.getUint16(at, true); at += 2;
-        return at;
-    },
-}
-
-function SpicePoint()
-{
-}
-
-SpicePoint.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.x = dv.getUint32(at, true); at += 4;
-        this.y = dv.getUint32(at, true); at += 4;
-        return at;
-    },
-}
-
-function SpiceCursorHeader()
-{
-}
-
-SpiceCursorHeader.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.unique = dv.getUint64(at, true); at += 8;
-        this.type = dv.getUint8(at, true); at ++;
-        this.width = dv.getUint16(at, true); at += 2;
-        this.height = dv.getUint16(at, true); at += 2;
-        this.hot_spot_x = dv.getUint16(at, true); at += 2;
-        this.hot_spot_y = dv.getUint16(at, true); at += 2;
-        return at;
-    },
-}
-
-function SpiceCursor()
-{
-}
-
-SpiceCursor.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.flags = dv.getUint16(at, true); at += 2;
-        if (this.flags & SPICE_CURSOR_FLAGS_NONE)
-            this.header = null;
-        else
-        {
-            this.header = new SpiceCursorHeader;
-            at = this.header.from_dv(dv, at, mb);
-            this.data   = mb.slice(at);
-            at += this.data.byteLength;
-        }
-        return at;
-    },
-}
-
-function SpiceSurface()
-{
-}
-
-SpiceSurface.prototype =
-{
-    from_dv: function(dv, at, mb)
-    {
-        this.surface_id = dv.getUint32(at, true); at += 4;
-        this.width = dv.getUint32(at, true); at += 4;
-        this.height = dv.getUint32(at, true); at += 4;
-        this.format = dv.getUint32(at, true); at += 4;
-        this.flags = dv.getUint32(at, true); at += 4;
-        return at;
-    },
-}
-
-/* FIXME - SpiceImage  types lz_plt, jpeg, zlib_glz, and jpeg_alpha are 
-           completely unimplemented */
diff -pruN 0.1.7-5/src/atKeynames.js 0.2.2-0ubuntu3/src/atKeynames.js
--- 0.1.7-5/src/atKeynames.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/atKeynames.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,189 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Thomas Roell not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Thomas Roell makes no representations
+ * about the suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * Copyright (c) 1994-2003 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * NOTE: The AT/MF keyboards can generate (via the 8042) two (MF: three)
+ *       sets of scancodes. Set3 can only be generated by a MF keyboard.
+ *       Set2 sends a makecode for keypress, and the same code prefixed by a
+ *       F0 for keyrelease. This is a little bit ugly to handle. Thus we use
+ *       here for X386 the PC/XT compatible Set1. This set uses 8bit scancodes.
+ *       Bit 7 ist set if the key is released. The code E0 switches to a
+ *       different meaning to add the new MF cursorkeys, while not breaking old
+ *       applications. E1 is another special prefix. Since I assume that there
+ *       will be further versions of PC/XT scancode compatible keyboards, we
+ *       may be in trouble one day.
+ *
+ * IDEA: 1) Use Set2 on AT84 keyboards and translate it to MF Set3.
+ *       2) Use the keyboards native set and translate it to common keysyms.
+ */
+
+
+var KeyNames = {
+/*
+ * definition of the AT84/MF101/MF102 Keyboard:
+ * ============================================================
+ *       Defined             Key Cap Glyphs       Pressed value
+ *      Key Name            Main       Also       (hex)    (dec)
+ *      ----------------   ---------- -------    ------    ------
+ */
+  KEY_Escape      :/* Escape                0x01  */    1,
+  KEY_1           :/* 1           !         0x02  */    2,
+  KEY_2           :/* 2           @         0x03  */    3,
+  KEY_3           :/* 3           #         0x04  */    4,
+  KEY_4           :/* 4           $         0x05  */    5,
+  KEY_5           :/* 5           %         0x06  */    6,
+  KEY_6           :/* 6           ^         0x07  */    7,
+  KEY_7           :/* 7           &         0x08  */    8,
+  KEY_8           :/* 8           *         0x09  */    9,
+  KEY_9           :/* 9           (         0x0a  */   10,
+  KEY_0           :/* 0           )         0x0b  */   11,
+  KEY_Minus       :/* - (Minus)   _ (Under) 0x0c  */   12,
+  KEY_Equal       :/* = (Equal)   +         0x0d  */   13,
+  KEY_BackSpace   :/* Back Space            0x0e  */   14,
+  KEY_Tab         :/* Tab                   0x0f  */   15,
+  KEY_Q           :/* Q                     0x10  */   16,
+  KEY_W           :/* W                     0x11  */   17,
+  KEY_E           :/* E                     0x12  */   18,
+  KEY_R           :/* R                     0x13  */   19,
+  KEY_T           :/* T                     0x14  */   20,
+  KEY_Y           :/* Y                     0x15  */   21,
+  KEY_U           :/* U                     0x16  */   22,
+  KEY_I           :/* I                     0x17  */   23,
+  KEY_O           :/* O                     0x18  */   24,
+  KEY_P           :/* P                     0x19  */   25,
+  KEY_LBrace      :/* [           {         0x1a  */   26,
+  KEY_RBrace      :/* ]           }         0x1b  */   27,
+  KEY_Enter       :/* Enter                 0x1c  */   28,
+  KEY_LCtrl       :/* Ctrl(left)            0x1d  */   29,
+  KEY_A           :/* A                     0x1e  */   30,
+  KEY_S           :/* S                     0x1f  */   31,
+  KEY_D           :/* D                     0x20  */   32,
+  KEY_F           :/* F                     0x21  */   33,
+  KEY_G           :/* G                     0x22  */   34,
+  KEY_H           :/* H                     0x23  */   35,
+  KEY_J           :/* J                     0x24  */   36,
+  KEY_K           :/* K                     0x25  */   37,
+  KEY_L           :/* L                     0x26  */   38,
+  KEY_SemiColon   :/* ;(SemiColon) :(Colon) 0x27  */   39,
+  KEY_Quote       :/* ' (Apostr)  " (Quote) 0x28  */   40,
+  KEY_Tilde       :/* ` (Accent)  ~ (Tilde) 0x29  */   41,
+  KEY_ShiftL      :/* Shift(left)           0x2a  */   42,
+  KEY_BSlash      :/* \(BckSlash) |(VertBar)0x2b  */   43,
+  KEY_Z           :/* Z                     0x2c  */   44,
+  KEY_X           :/* X                     0x2d  */   45,
+  KEY_C           :/* C                     0x2e  */   46,
+  KEY_V           :/* V                     0x2f  */   47,
+  KEY_B           :/* B                     0x30  */   48,
+  KEY_N           :/* N                     0x31  */   49,
+  KEY_M           :/* M                     0x32  */   50,
+  KEY_Comma       :/* , (Comma)   < (Less)  0x33  */   51,
+  KEY_Period      :/* . (Period)  >(Greater)0x34  */   52,
+  KEY_Slash       :/* / (Slash)   ?         0x35  */   53,
+  KEY_ShiftR      :/* Shift(right)          0x36  */   54,
+  KEY_KP_Multiply :/* *                     0x37  */   55,
+  KEY_Alt         :/* Alt(left)             0x38  */   56,
+  KEY_Space       :/*   (SpaceBar)          0x39  */   57,
+  KEY_CapsLock    :/* CapsLock              0x3a  */   58,
+  KEY_F1          :/* F1                    0x3b  */   59,
+  KEY_F2          :/* F2                    0x3c  */   60,
+  KEY_F3          :/* F3                    0x3d  */   61,
+  KEY_F4          :/* F4                    0x3e  */   62,
+  KEY_F5          :/* F5                    0x3f  */   63,
+  KEY_F6          :/* F6                    0x40  */   64,
+  KEY_F7          :/* F7                    0x41  */   65,
+  KEY_F8          :/* F8                    0x42  */   66,
+  KEY_F9          :/* F9                    0x43  */   67,
+  KEY_F10         :/* F10                   0x44  */   68,
+  KEY_NumLock     :/* NumLock               0x45  */   69,
+  KEY_ScrollLock  :/* ScrollLock            0x46  */   70,
+  KEY_KP_7        :/* 7           Home      0x47  */   71,
+  KEY_KP_8        :/* 8           Up        0x48  */   72,
+  KEY_KP_9        :/* 9           PgUp      0x49  */   73,
+  KEY_KP_Minus    :/* - (Minus)             0x4a  */   74,
+  KEY_KP_4        :/* 4           Left      0x4b  */   75,
+  KEY_KP_5        :/* 5                     0x4c  */   76,
+  KEY_KP_6        :/* 6           Right     0x4d  */   77,
+  KEY_KP_Plus     :/* + (Plus)              0x4e  */   78,
+  KEY_KP_1        :/* 1           End       0x4f  */   79,
+  KEY_KP_2        :/* 2           Down      0x50  */   80,
+  KEY_KP_3        :/* 3           PgDown    0x51  */   81,
+  KEY_KP_0        :/* 0           Insert    0x52  */   82,
+  KEY_KP_Decimal  :/* . (Decimal) Delete    0x53  */   83,
+  KEY_SysRequest  :/* SysRequest            0x54  */   84,
+                   /* NOTUSED               0x55  */
+  KEY_Less        :/* < (Less)   >(Greater) 0x56  */   86,
+  KEY_F11         :/* F11                   0x57  */   87,
+  KEY_F12         :/* F12                   0x58  */   88,
+
+  KEY_Prefix0     :/* special               0x60  */   96,
+  KEY_Prefix1     :/* specail               0x61  */   97,
+};
+
+export {
+  KeyNames,
+};
diff -pruN 0.1.7-5/src/bitmap.js 0.2.2-0ubuntu3/src/bitmap.js
--- 0.1.7-5/src/bitmap.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/bitmap.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,64 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*----------------------------------------------------------------------------
+**  bitmap.js
+**      Handle SPICE_IMAGE_TYPE_BITMAP
+**--------------------------------------------------------------------------*/
+
+import { Constants } from './enums.js';
+
+function convert_spice_bitmap_to_web(context, spice_bitmap)
+{
+    var ret;
+    var offset, x, src_offset = 0, src_dec = 0;
+    var u8 = new Uint8Array(spice_bitmap.data);
+    if (spice_bitmap.format != Constants.SPICE_BITMAP_FMT_32BIT &&
+        spice_bitmap.format != Constants.SPICE_BITMAP_FMT_RGBA)
+        return undefined;
+
+    if (!(spice_bitmap.flags & Constants.SPICE_BITMAP_FLAGS_TOP_DOWN))
+    {
+        src_offset = (spice_bitmap.y - 1 ) * spice_bitmap.stride;
+        src_dec = 2 * spice_bitmap.stride;
+    }
+
+    ret = context.createImageData(spice_bitmap.x, spice_bitmap.y);
+    for (offset = 0; offset < (spice_bitmap.y * spice_bitmap.stride); src_offset -= src_dec)
+        for (x = 0; x < spice_bitmap.x; x++, offset += 4, src_offset += 4)
+        {
+            ret.data[offset + 0 ] = u8[src_offset + 2];
+            ret.data[offset + 1 ] = u8[src_offset + 1];
+            ret.data[offset + 2 ] = u8[src_offset + 0];
+
+            // FIXME - We effectively treat all images as having SPICE_IMAGE_FLAGS_HIGH_BITS_SET
+            if (spice_bitmap.format == Constants.SPICE_BITMAP_FMT_32BIT)
+                ret.data[offset + 3] = 255;
+            else
+                ret.data[offset + 3] = u8[src_offset];
+        }
+
+    return ret;
+}
+
+export {
+  convert_spice_bitmap_to_web,
+};
diff -pruN 0.1.7-5/src/cursor.js 0.2.2-0ubuntu3/src/cursor.js
--- 0.1.7-5/src/cursor.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/cursor.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,141 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import { create_rgba_png } from './png.js';
+import { Constants } from './enums.js';
+import { DEBUG } from './utils.js';
+import {
+  SpiceMsgCursorInit,
+  SpiceMsgCursorSet,
+} from './spicemsg.js';
+import { SpiceSimulateCursor } from './simulatecursor.js';
+import { SpiceConn } from './spiceconn.js';
+
+/*----------------------------------------------------------------------------
+**  SpiceCursorConn
+**      Drive the Spice Cursor Channel
+**--------------------------------------------------------------------------*/
+function SpiceCursorConn()
+{
+    SpiceConn.apply(this, arguments);
+}
+
+SpiceCursorConn.prototype = Object.create(SpiceConn.prototype);
+SpiceCursorConn.prototype.process_channel_message = function(msg)
+{
+    if (msg.type == Constants.SPICE_MSG_CURSOR_INIT)
+    {
+        var cursor_init = new SpiceMsgCursorInit(msg.data);
+        DEBUG > 1 && console.log("SpiceMsgCursorInit");
+        if (this.parent && this.parent.inputs &&
+            this.parent.inputs.mouse_mode == Constants.SPICE_MOUSE_MODE_SERVER)
+        {
+            // FIXME - this imagines that the server actually
+            //          provides the current cursor position,
+            //          instead of 0,0.  As of May 11, 2012,
+            //          that assumption was false :-(.
+            this.parent.inputs.mousex = cursor_init.position.x;
+            this.parent.inputs.mousey = cursor_init.position.y;
+        }
+        // FIXME - We don't handle most of the parameters here...
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_CURSOR_SET)
+    {
+        var cursor_set = new SpiceMsgCursorSet(msg.data);
+        DEBUG > 1 && console.log("SpiceMsgCursorSet");
+        if (cursor_set.flags & Constants.SPICE_CURSOR_FLAGS_NONE)
+        {
+            document.getElementById(this.parent.screen_id).style.cursor = "none";
+            return true;
+        }
+
+        if (cursor_set.flags > 0)
+            this.log_warn("FIXME: No support for cursor flags " + cursor_set.flags);
+
+        if (cursor_set.cursor.header.type != Constants.SPICE_CURSOR_TYPE_ALPHA)
+        {
+            this.log_warn("FIXME: No support for cursor type " + cursor_set.cursor.header.type);
+            return false;
+        }
+
+        this.set_cursor(cursor_set.cursor);
+
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_CURSOR_MOVE)
+    {
+        this.known_unimplemented(msg.type, "Cursor Move");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_CURSOR_HIDE)
+    {
+        DEBUG > 1 && console.log("SpiceMsgCursorHide");
+        document.getElementById(this.parent.screen_id).style.cursor = "none";
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_CURSOR_TRAIL)
+    {
+        this.known_unimplemented(msg.type, "Cursor Trail");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_CURSOR_RESET)
+    {
+        DEBUG > 1 && console.log("SpiceMsgCursorReset");
+        document.getElementById(this.parent.screen_id).style.cursor = "auto";
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_CURSOR_INVAL_ONE)
+    {
+        this.known_unimplemented(msg.type, "Cursor Inval One");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_CURSOR_INVAL_ALL)
+    {
+        DEBUG > 1 && console.log("SpiceMsgCursorInvalAll");
+        // FIXME - There may be something useful to do here...
+        return true;
+    }
+
+    return false;
+}
+
+SpiceCursorConn.prototype.set_cursor = function(cursor)
+{
+    var pngstr = create_rgba_png(cursor.header.height, cursor.header.width, cursor.data);
+    var curstr = 'url(data:image/png,' + pngstr + ') ' +
+        cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default";
+    var screen = document.getElementById(this.parent.screen_id);
+    screen.style.cursor = 'auto';
+    screen.style.cursor = curstr;
+    if (window.getComputedStyle(screen, null).cursor == 'auto')
+        SpiceSimulateCursor.simulate_cursor(this, cursor, screen, pngstr);
+}
+
+export {
+  SpiceCursorConn,
+};
diff -pruN 0.1.7-5/src/display.js 0.2.2-0ubuntu3/src/display.js
--- 0.1.7-5/src/display.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/display.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,1267 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import * as Webm from './webm.js';
+import * as Messages from './spicemsg.js';
+import * as Quic from './quic.js';
+import * as Utils from './utils.js';
+import * as Inputs from './inputs.js';
+import { Constants } from './enums.js';
+import { SpiceConn } from './spiceconn.js';
+import { SpiceRect } from './spicetype.js';
+import { convert_spice_lz_to_web } from './lz.js';
+import { convert_spice_bitmap_to_web } from './bitmap.js';
+
+/*----------------------------------------------------------------------------
+**  FIXME: putImageData  does not support Alpha blending
+**           or compositing.  So if we have data in an ImageData
+**           format, we have to draw it onto a context,
+**           and then use drawImage to put it onto the target,
+**           as drawImage does alpha.
+**--------------------------------------------------------------------------*/
+function putImageDataWithAlpha(context, d, x, y)
+{
+    var c = document.createElement("canvas");
+    var t = c.getContext("2d");
+    c.setAttribute('width', d.width);
+    c.setAttribute('height', d.height);
+    t.putImageData(d, 0, 0);
+    context.drawImage(c, x, y, d.width, d.height);
+}
+
+/*----------------------------------------------------------------------------
+**  FIXME: Spice will send an image with '0' alpha when it is intended to
+**           go on a surface w/no alpha.  So in that case, we have to strip
+**           out the alpha.  The test case for this was flux box; in a Xspice
+**           server, right click on the desktop to get the menu; the top bar
+**           doesn't paint/highlight correctly w/out this change.
+**--------------------------------------------------------------------------*/
+function stripAlpha(d)
+{
+    var i;
+    for (i = 0; i < (d.width * d.height * 4); i += 4)
+        d.data[i + 3] = 255;
+}
+
+/*----------------------------------------------------------------------------
+**  SpiceDisplayConn
+**      Drive the Spice Display Channel
+**--------------------------------------------------------------------------*/
+function SpiceDisplayConn()
+{
+    SpiceConn.apply(this, arguments);
+}
+
+SpiceDisplayConn.prototype = Object.create(SpiceConn.prototype);
+SpiceDisplayConn.prototype.process_channel_message = function(msg)
+{
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_MODE)
+    {
+        this.known_unimplemented(msg.type, "Display Mode");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_MARK)
+    {
+        // FIXME - DISPLAY_MARK not implemented (may be hard or impossible)
+        this.known_unimplemented(msg.type, "Display Mark");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_RESET)
+    {
+        Utils.DEBUG > 2 && console.log("Display reset");
+        this.surfaces[this.primary_surface].canvas.context.restore();
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_COPY)
+    {
+        var draw_copy = new Messages.SpiceMsgDisplayDrawCopy(msg.data);
+
+        Utils.DEBUG > 1 && this.log_draw("DrawCopy", draw_copy);
+
+        if (! draw_copy.base.box.is_same_size(draw_copy.data.src_area))
+            this.log_warn("FIXME: DrawCopy src_area is a different size than base.box; we do not handle that yet.");
+        if (draw_copy.base.clip.type != Constants.SPICE_CLIP_TYPE_NONE)
+            this.log_warn("FIXME: DrawCopy we don't handle clipping yet");
+        if (draw_copy.data.rop_descriptor != Constants.SPICE_ROPD_OP_PUT)
+            this.log_warn("FIXME: DrawCopy we don't handle ropd type: " + draw_copy.data.rop_descriptor);
+        if (draw_copy.data.mask.flags)
+            this.log_warn("FIXME: DrawCopy we don't handle mask flag: " + draw_copy.data.mask.flags);
+        if (draw_copy.data.mask.bitmap)
+            this.log_warn("FIXME: DrawCopy we don't handle mask");
+
+        if (draw_copy.data && draw_copy.data.src_bitmap)
+        {
+            if (draw_copy.data.src_bitmap.descriptor.flags &&
+                draw_copy.data.src_bitmap.descriptor.flags != Constants.SPICE_IMAGE_FLAGS_CACHE_ME &&
+                draw_copy.data.src_bitmap.descriptor.flags != Constants.SPICE_IMAGE_FLAGS_HIGH_BITS_SET)
+            {
+                this.log_warn("FIXME: DrawCopy unhandled image flags: " + draw_copy.data.src_bitmap.descriptor.flags);
+                Utils.DEBUG <= 1 && this.log_draw("DrawCopy", draw_copy);
+            }
+
+            if (draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_QUIC)
+            {
+                var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+                if (! draw_copy.data.src_bitmap.quic)
+                {
+                    this.log_warn("FIXME: DrawCopy could not handle this QUIC file.");
+                    return false;
+                }
+                var source_img = Quic.convert_spice_quic_to_web(canvas.context,
+                                        draw_copy.data.src_bitmap.quic);
+
+                return this.draw_copy_helper(
+                    { base: draw_copy.base,
+                      src_area: draw_copy.data.src_area,
+                      image_data: source_img,
+                      tag: "copyquic." + draw_copy.data.src_bitmap.quic.type,
+                      has_alpha: (draw_copy.data.src_bitmap.quic.type == Quic.Constants.QUIC_IMAGE_TYPE_RGBA ? true : false) ,
+                      descriptor : draw_copy.data.src_bitmap.descriptor
+                    });
+            }
+            else if (draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_FROM_CACHE ||
+                    draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS)
+            {
+                if (! this.cache || ! this.cache[draw_copy.data.src_bitmap.descriptor.id])
+                {
+                    this.log_warn("FIXME: DrawCopy did not find image id " + draw_copy.data.src_bitmap.descriptor.id + " in cache.");
+                    return false;
+                }
+
+                return this.draw_copy_helper(
+                    { base: draw_copy.base,
+                      src_area: draw_copy.data.src_area,
+                      image_data: this.cache[draw_copy.data.src_bitmap.descriptor.id],
+                      tag: "copycache." + draw_copy.data.src_bitmap.descriptor.id,
+                      has_alpha: true, /* FIXME - may want this to be false... */
+                      descriptor : draw_copy.data.src_bitmap.descriptor
+                    });
+
+                /* FIXME - LOSSLESS CACHE ramifications not understood or handled */
+            }
+            else if (draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_SURFACE)
+            {
+                var source_context = this.surfaces[draw_copy.data.src_bitmap.surface_id].canvas.context;
+                var target_context = this.surfaces[draw_copy.base.surface_id].canvas.context;
+
+                var source_img = source_context.getImageData(
+                        draw_copy.data.src_area.left, draw_copy.data.src_area.top,
+                        draw_copy.data.src_area.right - draw_copy.data.src_area.left,
+                        draw_copy.data.src_area.bottom - draw_copy.data.src_area.top);
+                var computed_src_area = new SpiceRect;
+                computed_src_area.top = computed_src_area.left = 0;
+                computed_src_area.right = source_img.width;
+                computed_src_area.bottom = source_img.height;
+
+                /* FIXME - there is a potential optimization here.
+                           That is, if the surface is from 0,0, and
+                           both surfaces are alpha surfaces, you should
+                           be able to just do a drawImage, which should
+                           save time.  */
+
+                return this.draw_copy_helper(
+                    { base: draw_copy.base,
+                      src_area: computed_src_area,
+                      image_data: source_img,
+                      tag: "copysurf." + draw_copy.data.src_bitmap.surface_id,
+                      has_alpha: this.surfaces[draw_copy.data.src_bitmap.surface_id].format == Constants.SPICE_SURFACE_FMT_32_xRGB ? false : true,
+                      descriptor : draw_copy.data.src_bitmap.descriptor
+                    });
+            }
+            else if (draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_JPEG)
+            {
+                if (! draw_copy.data.src_bitmap.jpeg)
+                {
+                    this.log_warn("FIXME: DrawCopy could not handle this JPEG file.");
+                    return false;
+                }
+
+                // FIXME - how lame is this.  Be have it in binary format, and we have
+                //         to put it into string to get it back into jpeg.  Blech.
+                var tmpstr = "data:image/jpeg,";
+                var img = new Image;
+                var i;
+                var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg.data);
+                for (i = 0; i < qdv.length; i++)
+                {
+                    tmpstr +=  '%';
+                    if (qdv[i] < 16)
+                        tmpstr += '0';
+                    tmpstr += qdv[i].toString(16);
+                }
+
+                img.o =
+                    { base: draw_copy.base,
+                      tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
+                      descriptor : draw_copy.data.src_bitmap.descriptor,
+                      sc : this,
+                    };
+                img.onload = handle_draw_jpeg_onload;
+                img.src = tmpstr;
+
+                return true;
+            }
+            else if (draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_JPEG_ALPHA)
+            {
+                if (! draw_copy.data.src_bitmap.jpeg_alpha)
+                {
+                    this.log_warn("FIXME: DrawCopy could not handle this JPEG ALPHA file.");
+                    return false;
+                }
+
+                // FIXME - how lame is this.  Be have it in binary format, and we have
+                //         to put it into string to get it back into jpeg.  Blech.
+                var tmpstr = "data:image/jpeg,";
+                var img = new Image;
+                var i;
+                var qdv = new Uint8Array(draw_copy.data.src_bitmap.jpeg_alpha.data);
+                for (i = 0; i < qdv.length; i++)
+                {
+                    tmpstr +=  '%';
+                    if (qdv[i] < 16)
+                        tmpstr += '0';
+                    tmpstr += qdv[i].toString(16);
+                }
+
+                img.o =
+                    { base: draw_copy.base,
+                      tag: "jpeg." + draw_copy.data.src_bitmap.surface_id,
+                      descriptor : draw_copy.data.src_bitmap.descriptor,
+                      sc : this,
+                    };
+
+                if (this.surfaces[draw_copy.base.surface_id].format == Constants.SPICE_SURFACE_FMT_32_ARGB)
+                {
+
+                    var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+                    img.alpha_img = convert_spice_lz_to_web(canvas.context,
+                                            draw_copy.data.src_bitmap.jpeg_alpha.alpha);
+                }
+                img.onload = handle_draw_jpeg_onload;
+                img.src = tmpstr;
+
+                return true;
+            }
+            else if (draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_BITMAP)
+            {
+                var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+                if (! draw_copy.data.src_bitmap.bitmap)
+                {
+                    this.log_err("null bitmap");
+                    return false;
+                }
+
+                var source_img = convert_spice_bitmap_to_web(canvas.context,
+                                        draw_copy.data.src_bitmap.bitmap);
+                if (! source_img)
+                {
+                    this.log_warn("FIXME: Unable to interpret bitmap of format: " +
+                        draw_copy.data.src_bitmap.bitmap.format);
+                    return false;
+                }
+
+                return this.draw_copy_helper(
+                    { base: draw_copy.base,
+                      src_area: draw_copy.data.src_area,
+                      image_data: source_img,
+                      tag: "bitmap." + draw_copy.data.src_bitmap.bitmap.format,
+                      has_alpha: draw_copy.data.src_bitmap.bitmap == Constants.SPICE_BITMAP_FMT_32BIT ? false : true,
+                      descriptor : draw_copy.data.src_bitmap.descriptor
+                    });
+            }
+            else if (draw_copy.data.src_bitmap.descriptor.type == Constants.SPICE_IMAGE_TYPE_LZ_RGB)
+            {
+                var canvas = this.surfaces[draw_copy.base.surface_id].canvas;
+                if (! draw_copy.data.src_bitmap.lz_rgb)
+                {
+                    this.log_err("null lz_rgb ");
+                    return false;
+                }
+
+                var source_img = convert_spice_lz_to_web(canvas.context,
+                                            draw_copy.data.src_bitmap.lz_rgb);
+                if (! source_img)
+                {
+                    this.log_warn("FIXME: Unable to interpret bitmap of type: " +
+                        draw_copy.data.src_bitmap.lz_rgb.type);
+                    return false;
+                }
+
+                return this.draw_copy_helper(
+                    { base: draw_copy.base,
+                      src_area: draw_copy.data.src_area,
+                      image_data: source_img,
+                      tag: "lz_rgb." + draw_copy.data.src_bitmap.lz_rgb.type,
+                      has_alpha: draw_copy.data.src_bitmap.lz_rgb.type == Constants.LZ_IMAGE_TYPE_RGBA ? true : false ,
+                      descriptor : draw_copy.data.src_bitmap.descriptor
+                    });
+            }
+            else
+            {
+                this.log_warn("FIXME: DrawCopy unhandled image type: " + draw_copy.data.src_bitmap.descriptor.type);
+                this.log_draw("DrawCopy", draw_copy);
+                return false;
+            }
+        }
+
+        this.log_warn("FIXME: DrawCopy no src_bitmap.");
+        return false;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_FILL)
+    {
+        var draw_fill = new Messages.SpiceMsgDisplayDrawFill(msg.data);
+
+        Utils.DEBUG > 1 && this.log_draw("DrawFill", draw_fill);
+
+        if (draw_fill.data.rop_descriptor != Constants.SPICE_ROPD_OP_PUT)
+            this.log_warn("FIXME: DrawFill we don't handle ropd type: " + draw_fill.data.rop_descriptor);
+        if (draw_fill.data.mask.flags)
+            this.log_warn("FIXME: DrawFill we don't handle mask flag: " + draw_fill.data.mask.flags);
+        if (draw_fill.data.mask.bitmap)
+            this.log_warn("FIXME: DrawFill we don't handle mask");
+
+        if (draw_fill.data.brush.type == Constants.SPICE_BRUSH_TYPE_SOLID)
+        {
+            // FIXME - do brushes ever have alpha?
+            var color = draw_fill.data.brush.color & 0xffffff;
+            var color_str = "rgb(" + (color >> 16) + ", " + ((color >> 8) & 0xff) + ", " + (color & 0xff) + ")";
+            this.surfaces[draw_fill.base.surface_id].canvas.context.fillStyle = color_str;
+
+            this.surfaces[draw_fill.base.surface_id].canvas.context.fillRect(
+                draw_fill.base.box.left, draw_fill.base.box.top,
+                draw_fill.base.box.right - draw_fill.base.box.left,
+                draw_fill.base.box.bottom - draw_fill.base.box.top);
+
+            if (Utils.DUMP_DRAWS && this.parent.dump_id)
+            {
+                var debug_canvas = document.createElement("canvas");
+                debug_canvas.setAttribute('width', this.surfaces[draw_fill.base.surface_id].canvas.width);
+                debug_canvas.setAttribute('height', this.surfaces[draw_fill.base.surface_id].canvas.height);
+                debug_canvas.setAttribute('id', "fillbrush." + draw_fill.base.surface_id + "." + this.surfaces[draw_fill.base.surface_id].draw_count);
+                debug_canvas.getContext("2d").fillStyle = color_str;
+                debug_canvas.getContext("2d").fillRect(
+                    draw_fill.base.box.left, draw_fill.base.box.top,
+                    draw_fill.base.box.right - draw_fill.base.box.left,
+                    draw_fill.base.box.bottom - draw_fill.base.box.top);
+                document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
+            }
+
+            this.surfaces[draw_fill.base.surface_id].draw_count++;
+
+        }
+        else
+        {
+            this.log_warn("FIXME: DrawFill can't handle brush type: " + draw_fill.data.brush.type);
+        }
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_OPAQUE)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Opaque");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_BLEND)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Blend");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_BLACKNESS)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Blackness");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_WHITENESS)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Whiteness");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_INVERS)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Invers");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_ROP3)
+    {
+        this.known_unimplemented(msg.type, "Display Draw ROP3");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_STROKE)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Stroke");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_TRANSPARENT)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Transparent");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Alpha Blend");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_COPY_BITS)
+    {
+        var copy_bits = new Messages.SpiceMsgDisplayCopyBits(msg.data);
+
+        Utils.DEBUG > 1 && this.log_draw("CopyBits", copy_bits);
+
+        var source_canvas = this.surfaces[copy_bits.base.surface_id].canvas;
+        var source_context = source_canvas.context;
+
+        var width = source_canvas.width - copy_bits.src_pos.x;
+        var height = source_canvas.height - copy_bits.src_pos.y;
+        if (width > (copy_bits.base.box.right - copy_bits.base.box.left))
+            width = copy_bits.base.box.right - copy_bits.base.box.left;
+        if (height > (copy_bits.base.box.bottom - copy_bits.base.box.top))
+            height = copy_bits.base.box.bottom - copy_bits.base.box.top;
+
+        var source_img = source_context.getImageData(
+                copy_bits.src_pos.x, copy_bits.src_pos.y, width, height);
+        //source_context.putImageData(source_img, copy_bits.base.box.left, copy_bits.base.box.top);
+        putImageDataWithAlpha(source_context, source_img, copy_bits.base.box.left, copy_bits.base.box.top);
+
+        if (Utils.DUMP_DRAWS && this.parent.dump_id)
+        {
+            var debug_canvas = document.createElement("canvas");
+            debug_canvas.setAttribute('width', width);
+            debug_canvas.setAttribute('height', height);
+            debug_canvas.setAttribute('id', "copybits" + copy_bits.base.surface_id + "." + this.surfaces[copy_bits.base.surface_id].draw_count);
+            debug_canvas.getContext("2d").putImageData(source_img, 0, 0);
+            document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
+        }
+
+
+        this.surfaces[copy_bits.base.surface_id].draw_count++;
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS)
+    {
+        this.known_unimplemented(msg.type, "Display Inval All Pixmaps");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_INVAL_PALETTE)
+    {
+        this.known_unimplemented(msg.type, "Display Inval Palette");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES)
+    {
+        this.known_unimplemented(msg.type, "Inval All Palettes");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_SURFACE_CREATE)
+    {
+        if (! ("surfaces" in this))
+            this.surfaces = [];
+
+        var m = new Messages.SpiceMsgSurfaceCreate(msg.data);
+        Utils.DEBUG > 1 && console.log(this.type + ": MsgSurfaceCreate id " + m.surface.surface_id
+                                    + "; " + m.surface.width + "x" + m.surface.height
+                                    + "; format " + m.surface.format
+                                    + "; flags " + m.surface.flags);
+        if (m.surface.format != Constants.SPICE_SURFACE_FMT_32_xRGB &&
+            m.surface.format != Constants.SPICE_SURFACE_FMT_32_ARGB)
+        {
+            this.log_warn("FIXME: cannot handle surface format " + m.surface.format + " yet.");
+            return false;
+        }
+
+        var canvas = document.createElement("canvas");
+        canvas.setAttribute('width', m.surface.width);
+        canvas.setAttribute('height', m.surface.height);
+        canvas.setAttribute('id', "spice_surface_" + m.surface.surface_id);
+        canvas.setAttribute('tabindex', m.surface.surface_id);
+        canvas.context = canvas.getContext("2d");
+
+        if (Utils.DUMP_CANVASES && this.parent.dump_id)
+            document.getElementById(this.parent.dump_id).appendChild(canvas);
+
+        m.surface.canvas = canvas;
+        m.surface.draw_count = 0;
+        this.surfaces[m.surface.surface_id] = m.surface;
+
+        if (m.surface.flags & Constants.SPICE_SURFACE_FLAGS_PRIMARY)
+        {
+            this.primary_surface = m.surface.surface_id;
+
+            /* This .save() is done entirely to enable SPICE_MSG_DISPLAY_RESET */
+            canvas.context.save();
+            document.getElementById(this.parent.screen_id).appendChild(canvas);
+
+            /* We're going to leave width dynamic, but correctly set the height */
+            document.getElementById(this.parent.screen_id).style.height = m.surface.height + "px";
+            this.hook_events();
+        }
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_SURFACE_DESTROY)
+    {
+        var m = new Messages.SpiceMsgSurfaceDestroy(msg.data);
+        Utils.DEBUG > 1 && console.log(this.type + ": MsgSurfaceDestroy id " + m.surface_id);
+        this.delete_surface(m.surface_id);
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_CREATE)
+    {
+        var m = new Messages.SpiceMsgDisplayStreamCreate(msg.data);
+        Utils.STREAM_DEBUG > 0 && console.log(this.type + ": MsgStreamCreate id" + m.id + "; type " + m.codec_type +
+                                        "; width " + m.stream_width + "; height " + m.stream_height +
+                                        "; left " + m.dest.left + "; top " + m.dest.top
+                                        );
+        if (!this.streams)
+            this.streams = new Array();
+        if (this.streams[m.id])
+            console.log("Stream " + m.id + " already exists");
+        else
+            this.streams[m.id] = m;
+
+        if (m.codec_type == Constants.SPICE_VIDEO_CODEC_TYPE_VP8)
+        {
+            var media = new MediaSource();
+            var v = document.createElement("video");
+            v.src = window.URL.createObjectURL(media);
+
+            v.setAttribute('autoplay', true);
+            v.setAttribute('width', m.stream_width);
+            v.setAttribute('height', m.stream_height);
+
+            var left = m.dest.left;
+            var top = m.dest.top;
+            if (this.surfaces[m.surface_id] !== undefined)
+            {
+                left += this.surfaces[m.surface_id].canvas.offsetLeft;
+                top += this.surfaces[m.surface_id].canvas.offsetTop;
+            }
+            document.getElementById(this.parent.screen_id).appendChild(v);
+            v.setAttribute('style', "position: absolute; top:" + top + "px; left:" + left + "px;");
+
+            media.addEventListener('sourceopen', handle_video_source_open, false);
+            media.addEventListener('sourceended', handle_video_source_ended, false);
+            media.addEventListener('sourceclosed', handle_video_source_closed, false);
+
+            var s = this.streams[m.id];
+            s.video = v;
+            s.media = media;
+            s.queue = new Array();
+            s.start_time = 0;
+            s.cluster_time = 0;
+            s.append_okay = false;
+
+            media.stream = s;
+            media.spiceconn = this;
+            v.spice_stream = s;
+        }
+        else if (m.codec_type == Constants.SPICE_VIDEO_CODEC_TYPE_MJPEG)
+            this.streams[m.id].frames_loading = 0;
+        else
+            console.log("Unhandled stream codec: "+m.codec_type);
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_DATA ||
+        msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_DATA_SIZED)
+    {
+        var m;
+        if (msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_DATA_SIZED)
+            m = new Messages.SpiceMsgDisplayStreamDataSized(msg.data);
+        else
+            m = new Messages.SpiceMsgDisplayStreamData(msg.data);
+
+        if (!this.streams[m.base.id])
+        {
+            console.log("no stream for data");
+            return false;
+        }
+
+        var time_until_due = m.base.multi_media_time - this.parent.relative_now();
+
+        if (this.streams[m.base.id].codec_type === Constants.SPICE_VIDEO_CODEC_TYPE_MJPEG)
+            process_mjpeg_stream_data(this, m, time_until_due);
+
+        if (this.streams[m.base.id].codec_type === Constants.SPICE_VIDEO_CODEC_TYPE_VP8)
+            process_video_stream_data(this.streams[m.base.id], m);
+
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT)
+    {
+        var m = new Messages.SpiceMsgDisplayStreamActivateReport(msg.data);
+
+        var report = new Messages.SpiceMsgcDisplayStreamReport(m.stream_id, m.unique_id);
+        if (this.streams[m.stream_id])
+        {
+            this.streams[m.stream_id].report = report;
+            this.streams[m.stream_id].max_window_size = m.max_window_size;
+            this.streams[m.stream_id].timeout_ms = m.timeout_ms
+        }
+
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_CLIP)
+    {
+        var m = new Messages.SpiceMsgDisplayStreamClip(msg.data);
+        Utils.STREAM_DEBUG > 1 && console.log(this.type + ": MsgStreamClip id" + m.id);
+        this.streams[m.id].clip = m.clip;
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_DESTROY)
+    {
+        var m = new Messages.SpiceMsgDisplayStreamDestroy(msg.data);
+        Utils.STREAM_DEBUG > 0 && console.log(this.type + ": MsgStreamDestroy id" + m.id);
+
+        if (this.streams[m.id].codec_type == Constants.SPICE_VIDEO_CODEC_TYPE_VP8)
+        {
+            document.getElementById(this.parent.screen_id).removeChild(this.streams[m.id].video);
+            this.streams[m.id].source_buffer = null;
+            this.streams[m.id].media = null;
+            this.streams[m.id].video = null;
+        }
+        this.streams[m.id] = undefined;
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL)
+    {
+        this.known_unimplemented(msg.type, "Display Stream Destroy All");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_INVAL_LIST)
+    {
+        var m = new Messages.SpiceMsgDisplayInvalList(msg.data);
+        var i;
+        Utils.DEBUG > 1 && console.log(this.type + ": MsgInvalList " + m.count + " items");
+        for (i = 0; i < m.count; i++)
+            if (this.cache[m.resources[i].id] != undefined)
+                delete this.cache[m.resources[i].id];
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_MONITORS_CONFIG)
+    {
+        this.known_unimplemented(msg.type, "Display Monitors Config");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_DISPLAY_DRAW_COMPOSITE)
+    {
+        this.known_unimplemented(msg.type, "Display Draw Composite");
+        return true;
+    }
+
+    return false;
+}
+
+SpiceDisplayConn.prototype.delete_surface = function(surface_id)
+{
+    var canvas = document.getElementById("spice_surface_" + surface_id);
+    if (Utils.DUMP_CANVASES && this.parent.dump_id)
+        document.getElementById(this.parent.dump_id).removeChild(canvas);
+    if (this.primary_surface == surface_id)
+    {
+        this.unhook_events();
+        this.primary_surface = undefined;
+        document.getElementById(this.parent.screen_id).removeChild(canvas);
+    }
+
+    delete this.surfaces[surface_id];
+}
+
+
+SpiceDisplayConn.prototype.draw_copy_helper = function(o)
+{
+
+    var canvas = this.surfaces[o.base.surface_id].canvas;
+    if (o.has_alpha)
+    {
+        /* FIXME - This is based on trial + error, not a serious thoughtful
+                   analysis of what Spice requires.  See display.js for more. */
+        if (this.surfaces[o.base.surface_id].format == Constants.SPICE_SURFACE_FMT_32_xRGB)
+        {
+            stripAlpha(o.image_data);
+            canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
+        }
+        else
+            putImageDataWithAlpha(canvas.context, o.image_data,
+                    o.base.box.left, o.base.box.top);
+    }
+    else
+        canvas.context.putImageData(o.image_data, o.base.box.left, o.base.box.top);
+
+    if (o.src_area.left > 0 || o.src_area.top > 0)
+    {
+        this.log_warn("FIXME: DrawCopy not shifting draw copies just yet...");
+    }
+
+    if (o.descriptor && (o.descriptor.flags & Constants.SPICE_IMAGE_FLAGS_CACHE_ME))
+    {
+        if (! ("cache" in this))
+            this.cache = {};
+        this.cache[o.descriptor.id] = o.image_data;
+    }
+
+    if (Utils.DUMP_DRAWS && this.parent.dump_id)
+    {
+        var debug_canvas = document.createElement("canvas");
+        debug_canvas.setAttribute('width', o.image_data.width);
+        debug_canvas.setAttribute('height', o.image_data.height);
+        debug_canvas.setAttribute('id', o.tag + "." +
+            this.surfaces[o.base.surface_id].draw_count + "." +
+            o.base.surface_id + "@" + o.base.box.left + "x" +  o.base.box.top);
+        debug_canvas.getContext("2d").putImageData(o.image_data, 0, 0);
+        document.getElementById(this.parent.dump_id).appendChild(debug_canvas);
+    }
+
+    this.surfaces[o.base.surface_id].draw_count++;
+
+    return true;
+}
+
+
+SpiceDisplayConn.prototype.log_draw = function(prefix, draw)
+{
+    var str = prefix + "." + draw.base.surface_id + "." + this.surfaces[draw.base.surface_id].draw_count + ": ";
+    str += "base.box " + draw.base.box.left + ", " + draw.base.box.top + " to " +
+                           draw.base.box.right + ", " + draw.base.box.bottom;
+    str += "; clip.type " + draw.base.clip.type;
+
+    if (draw.data)
+    {
+        if (draw.data.src_area)
+            str += "; src_area " + draw.data.src_area.left + ", " + draw.data.src_area.top + " to "
+                                 + draw.data.src_area.right + ", " + draw.data.src_area.bottom;
+
+        if (draw.data.src_bitmap && draw.data.src_bitmap != null)
+        {
+            str += "; src_bitmap id: " + draw.data.src_bitmap.descriptor.id;
+            str += "; src_bitmap width " + draw.data.src_bitmap.descriptor.width + ", height " + draw.data.src_bitmap.descriptor.height;
+            str += "; src_bitmap type " + draw.data.src_bitmap.descriptor.type + ", flags " + draw.data.src_bitmap.descriptor.flags;
+            if (draw.data.src_bitmap.surface_id !== undefined)
+                str += "; src_bitmap surface_id " + draw.data.src_bitmap.surface_id;
+            if (draw.data.src_bitmap.bitmap)
+                str += "; BITMAP format " + draw.data.src_bitmap.bitmap.format +
+                        "; flags " + draw.data.src_bitmap.bitmap.flags +
+                        "; x " + draw.data.src_bitmap.bitmap.x +
+                        "; y " + draw.data.src_bitmap.bitmap.y +
+                        "; stride " + draw.data.src_bitmap.bitmap.stride ;
+            if (draw.data.src_bitmap.quic)
+                str += "; QUIC type " + draw.data.src_bitmap.quic.type +
+                        "; width " + draw.data.src_bitmap.quic.width +
+                        "; height " + draw.data.src_bitmap.quic.height ;
+            if (draw.data.src_bitmap.lz_rgb)
+                str += "; LZ_RGB length " + draw.data.src_bitmap.lz_rgb.length +
+                       "; magic " + draw.data.src_bitmap.lz_rgb.magic +
+                       "; version 0x" + draw.data.src_bitmap.lz_rgb.version.toString(16) +
+                       "; type " + draw.data.src_bitmap.lz_rgb.type +
+                       "; width " + draw.data.src_bitmap.lz_rgb.width +
+                       "; height " + draw.data.src_bitmap.lz_rgb.height +
+                       "; stride " + draw.data.src_bitmap.lz_rgb.stride +
+                       "; top down " + draw.data.src_bitmap.lz_rgb.top_down;
+        }
+        else
+            str += "; src_bitmap is null";
+
+        if (draw.data.brush)
+        {
+            if (draw.data.brush.type == Constants.SPICE_BRUSH_TYPE_SOLID)
+                str += "; brush.color 0x" + draw.data.brush.color.toString(16);
+            if (draw.data.brush.type == Constants.SPICE_BRUSH_TYPE_PATTERN)
+            {
+                str += "; brush.pat ";
+                if (draw.data.brush.pattern.pat != null)
+                    str += "[SpiceImage]";
+                else
+                    str += "[null]";
+                str += " at " + draw.data.brush.pattern.pos.x + ", " + draw.data.brush.pattern.pos.y;
+            }
+        }
+
+        str += "; rop_descriptor " + draw.data.rop_descriptor;
+        if (draw.data.scale_mode !== undefined)
+            str += "; scale_mode " + draw.data.scale_mode;
+        str += "; mask.flags " + draw.data.mask.flags;
+        str += "; mask.pos " + draw.data.mask.pos.x + ", " + draw.data.mask.pos.y;
+        if (draw.data.mask.bitmap != null)
+        {
+            str += "; mask.bitmap width " + draw.data.mask.bitmap.descriptor.width + ", height " + draw.data.mask.bitmap.descriptor.height;
+            str += "; mask.bitmap type " + draw.data.mask.bitmap.descriptor.type + ", flags " + draw.data.mask.bitmap.descriptor.flags;
+        }
+        else
+            str += "; mask.bitmap is null";
+    }
+
+    console.log(str);
+}
+
+SpiceDisplayConn.prototype.hook_events = function()
+{
+    if (this.primary_surface !== undefined)
+    {
+        var canvas = this.surfaces[this.primary_surface].canvas;
+        canvas.sc = this.parent;
+        canvas.addEventListener('mousemove', Inputs.handle_mousemove);
+        canvas.addEventListener('mousedown', Inputs.handle_mousedown);
+        canvas.addEventListener('contextmenu', Inputs.handle_contextmenu);
+        canvas.addEventListener('mouseup', Inputs.handle_mouseup);
+        canvas.addEventListener('keydown', Inputs.handle_keydown);
+        canvas.addEventListener('keyup', Inputs.handle_keyup);
+        canvas.addEventListener('mouseout', handle_mouseout);
+        canvas.addEventListener('mouseover', handle_mouseover);
+        canvas.addEventListener('wheel', Inputs.handle_mousewheel);
+        canvas.focus();
+    }
+}
+
+SpiceDisplayConn.prototype.unhook_events = function()
+{
+    if (this.primary_surface !== undefined)
+    {
+        var canvas = this.surfaces[this.primary_surface].canvas;
+        canvas.removeEventListener('mousemove', Inputs.handle_mousemove);
+        canvas.removeEventListener('mousedown', Inputs.handle_mousedown);
+        canvas.removeEventListener('contextmenu', Inputs.handle_contextmenu);
+        canvas.removeEventListener('mouseup', Inputs.handle_mouseup);
+        canvas.removeEventListener('keydown', Inputs.handle_keydown);
+        canvas.removeEventListener('keyup', Inputs.handle_keyup);
+        canvas.removeEventListener('mouseout', handle_mouseout);
+        canvas.removeEventListener('mouseover', handle_mouseover);
+        canvas.removeEventListener('wheel', Inputs.handle_mousewheel);
+    }
+}
+
+
+SpiceDisplayConn.prototype.destroy_surfaces = function()
+{
+    for (var s in this.surfaces)
+    {
+        this.delete_surface(this.surfaces[s].surface_id);
+    }
+
+    this.surfaces = undefined;
+}
+
+
+function handle_mouseover(e)
+{
+    this.focus();
+}
+
+function handle_mouseout(e)
+{
+    if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor)
+        this.sc.cursor.spice_simulated_cursor.style.display = 'none';
+    this.blur();
+}
+
+function handle_draw_jpeg_onload()
+{
+    var temp_canvas = null;
+    var context;
+
+    if (this.o.sc.streams[this.o.id])
+        this.o.sc.streams[this.o.id].frames_loading--;
+
+    /*------------------------------------------------------------
+    ** FIXME:
+    **  The helper should be extended to be able to handle actual HtmlImageElements
+    **  ...and the cache should be modified to do so as well
+    **----------------------------------------------------------*/
+    if (this.o.sc.surfaces[this.o.base.surface_id] === undefined)
+    {
+        // This can happen; if the jpeg image loads after our surface
+        //  has been destroyed (e.g. open a menu, close it quickly),
+        //  we'll find we have no surface.
+        Utils.DEBUG > 2 && this.o.sc.log_info("Discarding jpeg; presumed lost surface " + this.o.base.surface_id);
+        temp_canvas = document.createElement("canvas");
+        temp_canvas.setAttribute('width', this.o.base.box.right);
+        temp_canvas.setAttribute('height', this.o.base.box.bottom);
+        context = temp_canvas.getContext("2d");
+    }
+    else
+        context = this.o.sc.surfaces[this.o.base.surface_id].canvas.context;
+
+    if (this.alpha_img)
+    {
+        var c = document.createElement("canvas");
+        var t = c.getContext("2d");
+        c.setAttribute('width', this.alpha_img.width);
+        c.setAttribute('height', this.alpha_img.height);
+        t.putImageData(this.alpha_img, 0, 0);
+        t.globalCompositeOperation = 'source-in';
+        t.drawImage(this, 0, 0);
+
+        context.drawImage(c, this.o.base.box.left, this.o.base.box.top);
+
+        if (this.o.descriptor &&
+            (this.o.descriptor.flags & Constants.SPICE_IMAGE_FLAGS_CACHE_ME))
+        {
+            if (! ("cache" in this.o.sc))
+                this.o.sc.cache = {};
+
+            this.o.sc.cache[this.o.descriptor.id] =
+                t.getImageData(0, 0,
+                    this.alpha_img.width,
+                    this.alpha_img.height);
+        }
+    }
+    else
+    {
+        context.drawImage(this, this.o.base.box.left, this.o.base.box.top);
+
+        // Give the Garbage collector a clue to recycle this; avoids
+        //  fairly massive memory leaks during video playback
+        this.onload = undefined;
+        this.src = Utils.EMPTY_GIF_IMAGE;
+
+        if (this.o.descriptor &&
+            (this.o.descriptor.flags & Constants.SPICE_IMAGE_FLAGS_CACHE_ME))
+        {
+            if (! ("cache" in this.o.sc))
+                this.o.sc.cache = {};
+
+            this.o.sc.cache[this.o.descriptor.id] =
+                context.getImageData(this.o.base.box.left, this.o.base.box.top,
+                    this.o.base.box.right - this.o.base.box.left,
+                    this.o.base.box.bottom - this.o.base.box.top);
+        }
+    }
+
+    if (temp_canvas == null)
+    {
+        if (Utils.DUMP_DRAWS && this.o.sc.parent.dump_id)
+        {
+            var debug_canvas = document.createElement("canvas");
+            debug_canvas.setAttribute('id', this.o.tag + "." +
+                this.o.sc.surfaces[this.o.base.surface_id].draw_count + "." +
+                this.o.base.surface_id + "@" + this.o.base.box.left + "x" +  this.o.base.box.top);
+            debug_canvas.getContext("2d").drawImage(this, 0, 0);
+            document.getElementById(this.o.sc.parent.dump_id).appendChild(debug_canvas);
+        }
+
+        this.o.sc.surfaces[this.o.base.surface_id].draw_count++;
+    }
+
+    if (this.o.sc.streams[this.o.id] && "report" in this.o.sc.streams[this.o.id])
+        process_stream_data_report(this.o.sc, this.o.id, this.o.msg_mmtime, this.o.msg_mmtime - this.o.sc.parent.relative_now());
+}
+
+function process_mjpeg_stream_data(sc, m, time_until_due)
+{
+    /* If we are currently processing an mjpeg frame when a new one arrives,
+       and the new one is 'late', drop the new frame.  This helps the browsers
+       keep up, and provides rate control feedback as well */
+    if (time_until_due < 0 && sc.streams[m.base.id].frames_loading > 0)
+    {
+        if ("report" in sc.streams[m.base.id])
+            sc.streams[m.base.id].report.num_drops++;
+        return;
+    }
+
+    var tmpstr = "data:image/jpeg,";
+    var img = new Image;
+    var i;
+    for (i = 0; i < m.data.length; i++)
+    {
+        tmpstr +=  '%';
+        if (m.data[i] < 16)
+        tmpstr += '0';
+        tmpstr += m.data[i].toString(16);
+    }
+    var strm_base = new Messages.SpiceMsgDisplayBase();
+    strm_base.surface_id = sc.streams[m.base.id].surface_id;
+    strm_base.box = m.dest || sc.streams[m.base.id].dest;
+    strm_base.clip = sc.streams[m.base.id].clip;
+    img.o =
+        { base: strm_base,
+          tag: "mjpeg." + m.base.id,
+          descriptor: null,
+          sc : sc,
+          id : m.base.id,
+          msg_mmtime : m.base.multi_media_time,
+        };
+    img.onload = handle_draw_jpeg_onload;
+    img.src = tmpstr;
+
+    sc.streams[m.base.id].frames_loading++;
+}
+
+function process_stream_data_report(sc, id, msg_mmtime, time_until_due)
+{
+    sc.streams[id].report.num_frames++;
+    if (sc.streams[id].report.start_frame_mm_time == 0)
+        sc.streams[id].report.start_frame_mm_time = msg_mmtime;
+
+    if (sc.streams[id].report.num_frames > sc.streams[id].max_window_size ||
+        (msg_mmtime - sc.streams[id].report.start_frame_mm_time) > sc.streams[id].timeout_ms)
+    {
+        sc.streams[id].report.end_frame_mm_time = msg_mmtime;
+        sc.streams[id].report.last_frame_delay = time_until_due;
+
+        var msg = new Messages.SpiceMiniData();
+        msg.build_msg(Constants.SPICE_MSGC_DISPLAY_STREAM_REPORT, sc.streams[id].report);
+        sc.send_msg(msg);
+
+        sc.streams[id].report.start_frame_mm_time = 0;
+        sc.streams[id].report.num_frames = 0;
+        sc.streams[id].report.num_drops = 0;
+    }
+}
+
+function handle_video_source_open(e)
+{
+    var stream = this.stream;
+    var p = this.spiceconn;
+
+    if (stream.source_buffer)
+        return;
+
+    var s = this.addSourceBuffer(Webm.Constants.SPICE_VP8_CODEC);
+    if (! s)
+    {
+        p.log_err('Codec ' + Webm.Constants.SPICE_VP8_CODEC + ' not available.');
+        return;
+    }
+
+    stream.source_buffer = s;
+    s.spiceconn = p;
+    s.stream = stream;
+
+    listen_for_video_events(stream);
+
+    var h = new Webm.Header();
+    var te = new Webm.VideoTrackEntry(this.stream.stream_width, this.stream.stream_height);
+    var t = new Webm.Tracks(te);
+
+    var mb = new ArrayBuffer(h.buffer_size() + t.buffer_size())
+
+    var b = h.to_buffer(mb);
+    t.to_buffer(mb, b);
+
+    s.addEventListener('error', handle_video_buffer_error, false);
+    s.addEventListener('updateend', handle_append_video_buffer_done, false);
+
+    append_video_buffer(s, mb);
+}
+
+function handle_video_source_ended(e)
+{
+    var p = this.spiceconn;
+    p.log_err('Video source unexpectedly ended.');
+}
+
+function handle_video_source_closed(e)
+{
+    var p = this.spiceconn;
+    p.log_err('Video source unexpectedly closed.');
+}
+
+function append_video_buffer(sb, mb)
+{
+    try
+    {
+        sb.stream.append_okay = false;
+        sb.appendBuffer(mb);
+    }
+    catch (e)
+    {
+        var p = sb.spiceconn;
+        p.log_err("Error invoking appendBuffer: " + e.message);
+    }
+}
+
+function handle_append_video_buffer_done(e)
+{
+    var stream = this.stream;
+
+    if (stream.current_frame && "report" in stream)
+    {
+        var sc = this.stream.media.spiceconn;
+        var t = this.stream.current_frame.msg_mmtime;
+        process_stream_data_report(sc, stream.id, t, t - sc.parent.relative_now());
+    }
+
+    if (stream.queue.length > 0)
+    {
+        stream.current_frame = stream.queue.shift();
+        append_video_buffer(stream.source_buffer, stream.current_frame.mb);
+    }
+    else
+    {
+        stream.append_okay = true;
+    }
+
+    if (!stream.video)
+    {
+        if (Utils.STREAM_DEBUG > 0)
+            console.log("Stream id " + stream.id + " received updateend after video is gone.");
+        return;
+    }
+
+    if (stream.video.buffered.length > 0 &&
+        stream.video.currentTime < stream.video.buffered.start(stream.video.buffered.length - 1))
+    {
+        console.log("Video appears to have fallen behind; advancing to " +
+            stream.video.buffered.start(stream.video.buffered.length - 1));
+        stream.video.currentTime = stream.video.buffered.start(stream.video.buffered.length - 1);
+    }
+
+    if (Utils.STREAM_DEBUG > 1)
+        console.log(stream.video.currentTime + ":id " +  stream.id + " updateend " + Utils.dump_media_element(stream.video));
+}
+
+function handle_video_buffer_error(e)
+{
+    var p = this.spiceconn;
+    p.log_err('source_buffer error ' + e.message);
+}
+
+function push_or_queue(stream, msg, mb)
+{
+    var frame =
+    {
+        msg_mmtime : msg.base.multi_media_time,
+    };
+
+    if (stream.append_okay)
+    {
+        stream.current_frame = frame;
+        append_video_buffer(stream.source_buffer, mb);
+    }
+    else
+    {
+        frame.mb = mb;
+        stream.queue.push(frame);
+    }
+}
+
+function video_simple_block(stream, msg, keyframe)
+{
+    var simple = new Webm.SimpleBlock(msg.base.multi_media_time - stream.cluster_time, msg.data, keyframe);
+    var mb = new ArrayBuffer(simple.buffer_size());
+    simple.to_buffer(mb);
+
+    push_or_queue(stream, msg, mb);
+}
+
+function new_video_cluster(stream, msg)
+{
+    stream.cluster_time = msg.base.multi_media_time;
+    var c = new Webm.Cluster(stream.cluster_time - stream.start_time, msg.data);
+
+    var mb = new ArrayBuffer(c.buffer_size());
+    c.to_buffer(mb);
+
+    push_or_queue(stream, msg, mb);
+
+    video_simple_block(stream, msg, true);
+}
+
+function process_video_stream_data(stream, msg)
+{
+    if (stream.start_time == 0)
+    {
+        stream.start_time = msg.base.multi_media_time;
+        new_video_cluster(stream, msg);
+    }
+
+    else if (msg.base.multi_media_time - stream.cluster_time >= Webm.Constants.MAX_CLUSTER_TIME)
+        new_video_cluster(stream, msg);
+    else
+        video_simple_block(stream, msg, false);
+}
+
+function video_handle_event_debug(e)
+{
+    var s = this.spice_stream;
+    if (s.video)
+    {
+        if (Utils.STREAM_DEBUG > 0 || s.video.buffered.len > 1)
+            console.log(s.video.currentTime + ":id " +  s.id + " event " + e.type +
+                Utils.dump_media_element(s.video));
+    }
+
+    if (Utils.STREAM_DEBUG > 1 && s.media)
+        console.log("  media_source " + Utils.dump_media_source(s.media));
+
+    if (Utils.STREAM_DEBUG > 1 && s.source_buffer)
+        console.log("  source_buffer " + Utils.dump_source_buffer(s.source_buffer));
+
+    if (Utils.STREAM_DEBUG > 1 || s.queue.length > 1)
+        console.log('  queue len ' + s.queue.length + '; append_okay: ' + s.append_okay);
+}
+
+function video_debug_listen_for_one_event(name)
+{
+    this.addEventListener(name, video_handle_event_debug);
+}
+
+function listen_for_video_events(stream)
+{
+    var video_0_events = [
+        "abort", "error"
+    ];
+
+    var video_1_events = [
+        "loadstart", "suspend", "emptied", "stalled", "loadedmetadata", "loadeddata", "canplay",
+        "canplaythrough", "playing", "waiting", "seeking", "seeked", "ended", "durationchange",
+        "play", "pause", "ratechange"
+    ];
+
+    var video_2_events = [
+        "timeupdate",
+        "progress",
+        "resize",
+        "volumechange"
+    ];
+
+    video_0_events.forEach(video_debug_listen_for_one_event, stream.video);
+    if (Utils.STREAM_DEBUG > 0)
+        video_1_events.forEach(video_debug_listen_for_one_event, stream.video);
+    if (Utils.STREAM_DEBUG > 1)
+        video_2_events.forEach(video_debug_listen_for_one_event, stream.video);
+}
+
+export {
+  SpiceDisplayConn,
+};
diff -pruN 0.1.7-5/src/enums.js 0.2.2-0ubuntu3/src/enums.js
--- 0.1.7-5/src/enums.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/enums.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,372 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*----------------------------------------------------------------------------
+**  enums.js
+**      'constants' for Spice
+**--------------------------------------------------------------------------*/
+export var Constants = {
+  SPICE_MAGIC         : "REDQ",
+  SPICE_VERSION_MAJOR : 2,
+  SPICE_VERSION_MINOR : 2,
+
+  SPICE_CONNECT_TIMEOUT : (30 * 1000),
+
+  SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION : 0,
+  SPICE_COMMON_CAP_AUTH_SPICE              : 1,
+  SPICE_COMMON_CAP_AUTH_SASL               : 2,
+  SPICE_COMMON_CAP_MINI_HEADER             : 3,
+
+  SPICE_TICKET_KEY_PAIR_LENGTH             : 1024,
+  SPICE_TICKET_PUBKEY_BYTES                : (1024 / 8 +34), // (SPICE_TICKET_KEY_PAIR_LENGTH / 8 + 34)
+
+  SPICE_LINK_ERR_OK                        : 0,
+  SPICE_LINK_ERR_ERROR                     : 1,
+  SPICE_LINK_ERR_INVALID_MAGIC             : 2,
+  SPICE_LINK_ERR_INVALID_DATA              : 3,
+  SPICE_LINK_ERR_VERSION_MISMATCH          : 4,
+  SPICE_LINK_ERR_NEED_SECURED              : 5,
+  SPICE_LINK_ERR_NEED_UNSECURED            : 6,
+  SPICE_LINK_ERR_PERMISSION_DENIED         : 7,
+  SPICE_LINK_ERR_BAD_CONNECTION_ID         : 8,
+  SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE     : 9,
+
+  SPICE_MSG_MIGRATE                   : 1,
+  SPICE_MSG_MIGRATE_DATA              : 2,
+  SPICE_MSG_SET_ACK                   : 3,
+  SPICE_MSG_PING                      : 4,
+  SPICE_MSG_WAIT_FOR_CHANNELS         : 5,
+  SPICE_MSG_DISCONNECTING             : 6,
+  SPICE_MSG_NOTIFY                    : 7,
+  SPICE_MSG_LIST                      : 8,
+
+  SPICE_MSG_MAIN_MIGRATE_BEGIN        : 101,
+  SPICE_MSG_MAIN_MIGRATE_CANCEL       : 102,
+  SPICE_MSG_MAIN_INIT                 : 103,
+  SPICE_MSG_MAIN_CHANNELS_LIST        : 104,
+  SPICE_MSG_MAIN_MOUSE_MODE           : 105,
+  SPICE_MSG_MAIN_MULTI_MEDIA_TIME     : 106,
+  SPICE_MSG_MAIN_AGENT_CONNECTED      : 107,
+  SPICE_MSG_MAIN_AGENT_DISCONNECTED   : 108,
+  SPICE_MSG_MAIN_AGENT_DATA           : 109,
+  SPICE_MSG_MAIN_AGENT_TOKEN          : 110,
+  SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST  : 111,
+  SPICE_MSG_MAIN_MIGRATE_END          : 112,
+  SPICE_MSG_MAIN_NAME                 : 113,
+  SPICE_MSG_MAIN_UUID                 : 114,
+  SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS : 115,
+  SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS : 116,
+  SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK : 117,
+  SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK : 118,
+  SPICE_MSG_END_MAIN                  : 119,
+
+
+
+  SPICE_MSGC_ACK_SYNC                 : 1,
+  SPICE_MSGC_ACK                      : 2,
+  SPICE_MSGC_PONG                     : 3,
+  SPICE_MSGC_MIGRATE_FLUSH_MARK       : 4,
+  SPICE_MSGC_MIGRATE_DATA             : 5,
+  SPICE_MSGC_DISCONNECTING            : 6,
+
+
+  SPICE_MSGC_MAIN_CLIENT_INFO         : 101,
+  SPICE_MSGC_MAIN_MIGRATE_CONNECTED   : 102,
+  SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR : 103,
+  SPICE_MSGC_MAIN_ATTACH_CHANNELS     : 104,
+  SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST  : 105,
+  SPICE_MSGC_MAIN_AGENT_START         : 106,
+  SPICE_MSGC_MAIN_AGENT_DATA          : 107,
+  SPICE_MSGC_MAIN_AGENT_TOKEN         : 108,
+  SPICE_MSGC_MAIN_MIGRATE_END         : 109,
+  SPICE_MSGC_END_MAIN                 : 110,
+
+  SPICE_MSG_DISPLAY_MODE              : 101,
+  SPICE_MSG_DISPLAY_MARK              : 102,
+  SPICE_MSG_DISPLAY_RESET             : 103,
+  SPICE_MSG_DISPLAY_COPY_BITS         : 104,
+  SPICE_MSG_DISPLAY_INVAL_LIST        : 105,
+  SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS : 106,
+  SPICE_MSG_DISPLAY_INVAL_PALETTE     : 107,
+  SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES: 108,
+
+  SPICE_MSG_DISPLAY_STREAM_CREATE     : 122,
+  SPICE_MSG_DISPLAY_STREAM_DATA       : 123,
+  SPICE_MSG_DISPLAY_STREAM_CLIP       : 124,
+  SPICE_MSG_DISPLAY_STREAM_DESTROY    : 125,
+  SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL: 126,
+
+  SPICE_MSG_DISPLAY_DRAW_FILL         : 302,
+  SPICE_MSG_DISPLAY_DRAW_OPAQUE       : 303,
+  SPICE_MSG_DISPLAY_DRAW_COPY         : 304,
+  SPICE_MSG_DISPLAY_DRAW_BLEND        : 305,
+  SPICE_MSG_DISPLAY_DRAW_BLACKNESS    : 306,
+  SPICE_MSG_DISPLAY_DRAW_WHITENESS    : 307,
+  SPICE_MSG_DISPLAY_DRAW_INVERS       : 308,
+  SPICE_MSG_DISPLAY_DRAW_ROP3         : 309,
+  SPICE_MSG_DISPLAY_DRAW_STROKE       : 310,
+  SPICE_MSG_DISPLAY_DRAW_TEXT         : 311,
+  SPICE_MSG_DISPLAY_DRAW_TRANSPARENT  : 312,
+  SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND  : 313,
+  SPICE_MSG_DISPLAY_SURFACE_CREATE    : 314,
+  SPICE_MSG_DISPLAY_SURFACE_DESTROY   : 315,
+  SPICE_MSG_DISPLAY_STREAM_DATA_SIZED : 316,
+  SPICE_MSG_DISPLAY_MONITORS_CONFIG   : 317,
+  SPICE_MSG_DISPLAY_DRAW_COMPOSITE    : 318,
+  SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT : 319,
+
+  SPICE_MSGC_DISPLAY_INIT             : 101,
+  SPICE_MSGC_DISPLAY_STREAM_REPORT    : 102,
+
+  SPICE_MSG_INPUTS_INIT               : 101,
+  SPICE_MSG_INPUTS_KEY_MODIFIERS      : 102,
+
+  SPICE_MSG_INPUTS_MOUSE_MOTION_ACK   : 111,
+
+  SPICE_MSGC_INPUTS_KEY_DOWN          : 101,
+  SPICE_MSGC_INPUTS_KEY_UP            : 102,
+  SPICE_MSGC_INPUTS_KEY_MODIFIERS     : 103,
+
+  SPICE_MSGC_INPUTS_MOUSE_MOTION      : 111,
+  SPICE_MSGC_INPUTS_MOUSE_POSITION    : 112,
+  SPICE_MSGC_INPUTS_MOUSE_PRESS       : 113,
+  SPICE_MSGC_INPUTS_MOUSE_RELEASE     : 114,
+
+  SPICE_MSG_CURSOR_INIT               : 101,
+  SPICE_MSG_CURSOR_RESET              : 102,
+  SPICE_MSG_CURSOR_SET                : 103,
+  SPICE_MSG_CURSOR_MOVE               : 104,
+  SPICE_MSG_CURSOR_HIDE               : 105,
+  SPICE_MSG_CURSOR_TRAIL              : 106,
+  SPICE_MSG_CURSOR_INVAL_ONE          : 107,
+  SPICE_MSG_CURSOR_INVAL_ALL          : 108,
+
+  SPICE_MSG_PLAYBACK_DATA             : 101,
+  SPICE_MSG_PLAYBACK_MODE             : 102,
+  SPICE_MSG_PLAYBACK_START            : 103,
+  SPICE_MSG_PLAYBACK_STOP             : 104,
+  SPICE_MSG_PLAYBACK_VOLUME           : 105,
+  SPICE_MSG_PLAYBACK_MUTE             : 106,
+  SPICE_MSG_PLAYBACK_LATENCY          : 107,
+
+  SPICE_MSG_SPICEVMC_DATA             : 101,
+  SPICE_MSG_PORT_INIT                 : 201,
+  SPICE_MSG_PORT_EVENT                : 202,
+  SPICE_MSG_END_PORT                  : 203,
+
+  SPICE_MSGC_SPICEVMC_DATA            : 101,
+  SPICE_MSGC_PORT_EVENT               : 201,
+  SPICE_MSGC_END_PORT                 : 202,
+
+  SPICE_PLAYBACK_CAP_CELT_0_5_1       : 0,
+  SPICE_PLAYBACK_CAP_VOLUME           : 1,
+  SPICE_PLAYBACK_CAP_LATENCY          : 2,
+  SPICE_PLAYBACK_CAP_OPUS             : 3,
+
+  SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE  : 0,
+  SPICE_MAIN_CAP_NAME_AND_UUID          : 1,
+  SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS : 2,
+  SPICE_MAIN_CAP_SEAMLESS_MIGRATE       : 3,
+
+  SPICE_DISPLAY_CAP_SIZED_STREAM        : 0,
+  SPICE_DISPLAY_CAP_MONITORS_CONFIG     : 1,
+  SPICE_DISPLAY_CAP_COMPOSITE           : 2,
+  SPICE_DISPLAY_CAP_A8_SURFACE          : 3,
+  SPICE_DISPLAY_CAP_STREAM_REPORT       : 4,
+  SPICE_DISPLAY_CAP_LZ4_COMPRESSION     : 5,
+  SPICE_DISPLAY_CAP_PREF_COMPRESSION    : 6,
+  SPICE_DISPLAY_CAP_GL_SCANOUT          : 7,
+  SPICE_DISPLAY_CAP_MULTI_CODEC         : 8,
+  SPICE_DISPLAY_CAP_CODEC_MJPEG         : 9,
+  SPICE_DISPLAY_CAP_CODEC_VP8           : 10,
+
+  SPICE_AUDIO_DATA_MODE_INVALID       : 0,
+  SPICE_AUDIO_DATA_MODE_RAW           : 1,
+  SPICE_AUDIO_DATA_MODE_CELT_0_5_1    : 2,
+  SPICE_AUDIO_DATA_MODE_OPUS          : 3,
+
+  SPICE_AUDIO_FMT_INVALID             : 0,
+  SPICE_AUDIO_FMT_S16                 : 1,
+
+  SPICE_CHANNEL_MAIN                  : 1,
+  SPICE_CHANNEL_DISPLAY               : 2,
+  SPICE_CHANNEL_INPUTS                : 3,
+  SPICE_CHANNEL_CURSOR                : 4,
+  SPICE_CHANNEL_PLAYBACK              : 5,
+  SPICE_CHANNEL_RECORD                : 6,
+  SPICE_CHANNEL_TUNNEL                : 7,
+  SPICE_CHANNEL_SMARTCARD             : 8,
+  SPICE_CHANNEL_USBREDIR              : 9,
+  SPICE_CHANNEL_PORT                  : 10,
+  SPICE_CHANNEL_WEBDAV                : 11,
+
+  SPICE_SURFACE_FLAGS_PRIMARY : (1 << 0),
+
+  SPICE_NOTIFY_SEVERITY_INFO  : 0,
+  SPICE_NOTIFY_SEVERITY_WARN  : 1,
+  SPICE_NOTIFY_SEVERITY_ERROR : 2,
+
+  SPICE_MOUSE_MODE_SERVER : (1 << 0),
+  SPICE_MOUSE_MODE_CLIENT : (1 << 1),
+  SPICE_MOUSE_MODE_MASK : 0x3,
+
+  SPICE_CLIP_TYPE_NONE            : 0,
+  SPICE_CLIP_TYPE_RECTS           : 1,
+
+  SPICE_IMAGE_TYPE_BITMAP         : 0,
+  SPICE_IMAGE_TYPE_QUIC           : 1,
+  SPICE_IMAGE_TYPE_RESERVED       : 2,
+  SPICE_IMAGE_TYPE_LZ_PLT         : 100,
+  SPICE_IMAGE_TYPE_LZ_RGB         : 101,
+  SPICE_IMAGE_TYPE_GLZ_RGB        : 102,
+  SPICE_IMAGE_TYPE_FROM_CACHE     : 103,
+  SPICE_IMAGE_TYPE_SURFACE        : 104,
+  SPICE_IMAGE_TYPE_JPEG           : 105,
+  SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS : 106,
+  SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB   : 107,
+  SPICE_IMAGE_TYPE_JPEG_ALPHA     : 108,
+
+  SPICE_IMAGE_FLAGS_CACHE_ME : (1 << 0),
+  SPICE_IMAGE_FLAGS_HIGH_BITS_SET : (1 << 1),
+  SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME : (1 << 2),
+
+  SPICE_BITMAP_FLAGS_PAL_CACHE_ME : (1 << 0),
+  SPICE_BITMAP_FLAGS_PAL_FROM_CACHE : (1 << 1),
+  SPICE_BITMAP_FLAGS_TOP_DOWN : (1 << 2),
+  SPICE_BITMAP_FLAGS_MASK : 0x7,
+
+  SPICE_BITMAP_FMT_INVALID        : 0,
+  SPICE_BITMAP_FMT_1BIT_LE        : 1,
+  SPICE_BITMAP_FMT_1BIT_BE        : 2,
+  SPICE_BITMAP_FMT_4BIT_LE        : 3,
+  SPICE_BITMAP_FMT_4BIT_BE        : 4,
+  SPICE_BITMAP_FMT_8BIT           : 5,
+  SPICE_BITMAP_FMT_16BIT          : 6,
+  SPICE_BITMAP_FMT_24BIT          : 7,
+  SPICE_BITMAP_FMT_32BIT          : 8,
+  SPICE_BITMAP_FMT_RGBA           : 9,
+
+
+  SPICE_CURSOR_FLAGS_NONE : (1 << 0),
+  SPICE_CURSOR_FLAGS_CACHE_ME : (1 << 1),
+  SPICE_CURSOR_FLAGS_FROM_CACHE : (1 << 2),
+  SPICE_CURSOR_FLAGS_MASK : 0x7,
+
+  SPICE_MOUSE_BUTTON_MASK_LEFT : (1 << 0),
+  SPICE_MOUSE_BUTTON_MASK_MIDDLE : (1 << 1),
+  SPICE_MOUSE_BUTTON_MASK_RIGHT : (1 << 2),
+  SPICE_MOUSE_BUTTON_MASK_MASK : 0x7,
+
+  SPICE_MOUSE_BUTTON_INVALID  : 0,
+  SPICE_MOUSE_BUTTON_LEFT     : 1,
+  SPICE_MOUSE_BUTTON_MIDDLE   : 2,
+  SPICE_MOUSE_BUTTON_RIGHT    : 3,
+  SPICE_MOUSE_BUTTON_UP       : 4,
+  SPICE_MOUSE_BUTTON_DOWN     : 5,
+
+  SPICE_BRUSH_TYPE_NONE : 0,
+  SPICE_BRUSH_TYPE_SOLID : 1,
+  SPICE_BRUSH_TYPE_PATTERN : 2,
+
+  SPICE_SURFACE_FMT_INVALID : 0,
+  SPICE_SURFACE_FMT_1_A : 1,
+  SPICE_SURFACE_FMT_8_A : 8,
+  SPICE_SURFACE_FMT_16_555 : 16,
+  SPICE_SURFACE_FMT_32_xRGB : 32,
+  SPICE_SURFACE_FMT_16_565 : 80,
+  SPICE_SURFACE_FMT_32_ARGB : 96,
+
+  SPICE_ROPD_INVERS_SRC : (1 << 0),
+  SPICE_ROPD_INVERS_BRUSH : (1 << 1),
+  SPICE_ROPD_INVERS_DEST : (1 << 2),
+  SPICE_ROPD_OP_PUT : (1 << 3),
+  SPICE_ROPD_OP_OR : (1 << 4),
+  SPICE_ROPD_OP_AND : (1 << 5),
+  SPICE_ROPD_OP_XOR : (1 << 6),
+  SPICE_ROPD_OP_BLACKNESS : (1 << 7),
+  SPICE_ROPD_OP_WHITENESS : (1 << 8),
+  SPICE_ROPD_OP_INVERS : (1 << 9),
+  SPICE_ROPD_INVERS_RES : (1 << 10),
+  SPICE_ROPD_MASK : 0x7ff,
+
+  LZ_IMAGE_TYPE_INVALID : 0,
+  LZ_IMAGE_TYPE_PLT1_LE : 1,
+  LZ_IMAGE_TYPE_PLT1_BE : 2,      // PLT stands for palette
+  LZ_IMAGE_TYPE_PLT4_LE : 3,
+  LZ_IMAGE_TYPE_PLT4_BE : 4,
+  LZ_IMAGE_TYPE_PLT8    : 5,
+  LZ_IMAGE_TYPE_RGB16   : 6,
+  LZ_IMAGE_TYPE_RGB24   : 7,
+  LZ_IMAGE_TYPE_RGB32   : 8,
+  LZ_IMAGE_TYPE_RGBA    : 9,
+  LZ_IMAGE_TYPE_XXXA    : 10,
+
+
+  SPICE_INPUT_MOTION_ACK_BUNCH : 4,
+
+
+  SPICE_CURSOR_TYPE_ALPHA     : 0,
+  SPICE_CURSOR_TYPE_MONO      : 1,
+  SPICE_CURSOR_TYPE_COLOR4    : 2,
+  SPICE_CURSOR_TYPE_COLOR8    : 3,
+  SPICE_CURSOR_TYPE_COLOR16   : 4,
+  SPICE_CURSOR_TYPE_COLOR24   : 5,
+  SPICE_CURSOR_TYPE_COLOR32   : 6,
+
+  SPICE_VIDEO_CODEC_TYPE_MJPEG : 1,
+  SPICE_VIDEO_CODEC_TYPE_VP8   : 2,
+
+  VD_AGENT_PROTOCOL : 1,
+  VD_AGENT_MAX_DATA_SIZE : 2048,
+
+  VD_AGENT_MOUSE_STATE            : 1,
+  VD_AGENT_MONITORS_CONFIG        : 2,
+  VD_AGENT_REPLY                  : 3,
+  VD_AGENT_CLIPBOARD              : 4,
+  VD_AGENT_DISPLAY_CONFIG         : 5,
+  VD_AGENT_ANNOUNCE_CAPABILITIES  : 6,
+  VD_AGENT_CLIPBOARD_GRAB         : 7,
+  VD_AGENT_CLIPBOARD_REQUEST      : 8,
+  VD_AGENT_CLIPBOARD_RELEASE      : 9,
+  VD_AGENT_FILE_XFER_START        :10,
+  VD_AGENT_FILE_XFER_STATUS       :11,
+  VD_AGENT_FILE_XFER_DATA         :12,
+  VD_AGENT_CLIENT_DISCONNECTED    :13,
+  VD_AGENT_MAX_CLIPBOARD          :14,
+
+  VD_AGENT_CAP_MOUSE_STATE            : 0,
+  VD_AGENT_CAP_MONITORS_CONFIG        : 1,
+  VD_AGENT_CAP_REPLY                  : 2,
+  VD_AGENT_CAP_CLIPBOARD              : 3,
+  VD_AGENT_CAP_DISPLAY_CONFIG         : 4,
+  VD_AGENT_CAP_CLIPBOARD_BY_DEMAND    : 5,
+  VD_AGENT_CAP_CLIPBOARD_SELECTION    : 6,
+  VD_AGENT_CAP_SPARSE_MONITORS_CONFIG : 7,
+  VD_AGENT_CAP_GUEST_LINEEND_LF       : 8,
+  VD_AGENT_CAP_GUEST_LINEEND_CRLF     : 9,
+  VD_AGENT_CAP_MAX_CLIPBOARD          : 10,
+  VD_AGENT_END_CAP                    : 11,
+
+  VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA : 0,
+  VD_AGENT_FILE_XFER_STATUS_CANCELLED     : 1,
+  VD_AGENT_FILE_XFER_STATUS_ERROR         : 2,
+  VD_AGENT_FILE_XFER_STATUS_SUCCESS       : 3,
+};
diff -pruN 0.1.7-5/src/filexfer.js 0.2.2-0ubuntu3/src/filexfer.js
--- 0.1.7-5/src/filexfer.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/filexfer.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,94 @@
+"use strict";
+/*
+   Copyright (C) 2014 Red Hat, Inc.
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+function SpiceFileXferTask(id, file)
+{
+    this.id = id;
+    this.file = file;
+}
+
+SpiceFileXferTask.prototype.create_progressbar = function()
+{
+    var _this = this;
+    var cancel = document.createElement("input");
+    this.progressbar_container = document.createElement("div");
+    this.progressbar = document.createElement("progress");
+
+    cancel.type = 'button';
+    cancel.value = 'Cancel';
+    cancel.style.float = 'right';
+    cancel.onclick = function()
+    {
+        _this.cancelled = true;
+        _this.remove_progressbar();
+    };
+
+    this.progressbar.setAttribute('max', this.file.size);
+    this.progressbar.setAttribute('value', 0);
+    this.progressbar.style.width = '100%';
+    this.progressbar.style.margin = '4px auto';
+    this.progressbar.style.display = 'inline-block';
+    this.progressbar_container.style.width = '90%';
+    this.progressbar_container.style.margin = 'auto';
+    this.progressbar_container.style.padding = '4px';
+    this.progressbar_container.textContent = this.file.name;
+    this.progressbar_container.appendChild(cancel);
+    this.progressbar_container.appendChild(this.progressbar);
+    document.getElementById('spice-xfer-area').appendChild(this.progressbar_container);
+}
+
+SpiceFileXferTask.prototype.update_progressbar = function(value)
+{
+    this.progressbar.setAttribute('value', value);
+}
+
+SpiceFileXferTask.prototype.remove_progressbar = function()
+{
+    if (this.progressbar_container && this.progressbar_container.parentNode)
+        this.progressbar_container.parentNode.removeChild(this.progressbar_container);
+}
+
+function handle_file_dragover(e)
+{
+    e.stopPropagation();
+    e.preventDefault();
+    e.dataTransfer.dropEffect = 'copy';
+}
+
+function handle_file_drop(e)
+{
+    var sc = window.spice_connection;
+    var files = e.dataTransfer.files;
+
+    e.stopPropagation();
+    e.preventDefault();
+    for (var i = files.length - 1; i >= 0; i--)
+    {
+        if (files[i].type) // do not copy a directory
+            sc.file_xfer_start(files[i]);
+    }
+
+}
+
+export {
+  SpiceFileXferTask,
+  handle_file_dragover,
+  handle_file_drop,
+};
diff -pruN 0.1.7-5/src/inputs.js 0.2.2-0ubuntu3/src/inputs.js
--- 0.1.7-5/src/inputs.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/inputs.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,298 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import * as Messages from './spicemsg.js';
+import { Constants } from './enums.js';
+import { KeyNames } from './atKeynames.js';
+import { SpiceConn } from './spiceconn.js';
+import { DEBUG } from './utils.js';
+
+/*----------------------------------------------------------------------------
+ ** Modifier Keystates
+ **     These need to be tracked because focus in and out can get the keyboard
+ **     out of sync.
+ **------------------------------------------------------------------------*/
+var Shift_state = -1;
+var Ctrl_state = -1;
+var Alt_state = -1;
+var Meta_state = -1;
+
+/*----------------------------------------------------------------------------
+**  SpiceInputsConn
+**      Drive the Spice Inputs channel (e.g. mouse + keyboard)
+**--------------------------------------------------------------------------*/
+function SpiceInputsConn()
+{
+    SpiceConn.apply(this, arguments);
+
+    this.mousex = undefined;
+    this.mousey = undefined;
+    this.button_state = 0;
+    this.waiting_for_ack = 0;
+}
+
+SpiceInputsConn.prototype = Object.create(SpiceConn.prototype);
+SpiceInputsConn.prototype.process_channel_message = function(msg)
+{
+    if (msg.type == Constants.SPICE_MSG_INPUTS_INIT)
+    {
+        var inputs_init = new Messages.SpiceMsgInputsInit(msg.data);
+        this.keyboard_modifiers = inputs_init.keyboard_modifiers;
+        DEBUG > 1 && console.log("MsgInputsInit - modifier " + this.keyboard_modifiers);
+        // FIXME - We don't do anything with the keyboard modifiers...
+        return true;
+    }
+    if (msg.type == Constants.SPICE_MSG_INPUTS_KEY_MODIFIERS)
+    {
+        var key = new Messages.SpiceMsgInputsKeyModifiers(msg.data);
+        this.keyboard_modifiers = key.keyboard_modifiers;
+        DEBUG > 1 && console.log("MsgInputsKeyModifiers - modifier " + this.keyboard_modifiers);
+        // FIXME - We don't do anything with the keyboard modifiers...
+        return true;
+    }
+    if (msg.type == Constants.SPICE_MSG_INPUTS_MOUSE_MOTION_ACK)
+    {
+        DEBUG > 1 && console.log("mouse motion ack");
+        this.waiting_for_ack -= Constants.SPICE_INPUT_MOTION_ACK_BUNCH;
+        return true;
+    }
+    return false;
+}
+
+
+
+function handle_mousemove(e)
+{
+    var msg = new Messages.SpiceMiniData();
+    var move;
+    if (this.sc.mouse_mode == Constants.SPICE_MOUSE_MODE_CLIENT)
+    {
+        move = new Messages.SpiceMsgcMousePosition(this.sc, e)
+        msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_POSITION, move);
+    }
+    else
+    {
+        move = new Messages.SpiceMsgcMouseMotion(this.sc, e)
+        msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_MOTION, move);
+    }
+    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+    {
+        if (this.sc.inputs.waiting_for_ack < (2 * Constants.SPICE_INPUT_MOTION_ACK_BUNCH))
+        {
+            this.sc.inputs.send_msg(msg);
+            this.sc.inputs.waiting_for_ack++;
+        }
+        else
+        {
+            DEBUG > 0 && this.sc.log_info("Discarding mouse motion");
+        }
+    }
+
+    if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor)
+    {
+        this.sc.cursor.spice_simulated_cursor.style.display = 'block';
+        this.sc.cursor.spice_simulated_cursor.style.left = e.pageX - this.sc.cursor.spice_simulated_cursor.spice_hot_x + 'px';
+        this.sc.cursor.spice_simulated_cursor.style.top = e.pageY - this.sc.cursor.spice_simulated_cursor.spice_hot_y + 'px';
+        e.preventDefault();
+    }
+
+}
+
+function handle_mousedown(e)
+{
+    var press = new Messages.SpiceMsgcMousePress(this.sc, e)
+    var msg = new Messages.SpiceMiniData();
+    msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_PRESS, press);
+    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+        this.sc.inputs.send_msg(msg);
+
+    e.preventDefault();
+}
+
+function handle_contextmenu(e)
+{
+    e.preventDefault();
+    return false;
+}
+
+function handle_mouseup(e)
+{
+    var release = new Messages.SpiceMsgcMouseRelease(this.sc, e)
+    var msg = new Messages.SpiceMiniData();
+    msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_RELEASE, release);
+    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+        this.sc.inputs.send_msg(msg);
+
+    e.preventDefault();
+}
+
+function handle_mousewheel(e)
+{
+    var press = new Messages.SpiceMsgcMousePress;
+    var release = new Messages.SpiceMsgcMouseRelease;
+    if (e.deltaY < 0)
+        press.button = release.button = Constants.SPICE_MOUSE_BUTTON_UP;
+    else
+        press.button = release.button = Constants.SPICE_MOUSE_BUTTON_DOWN;
+    press.buttons_state = 0;
+    release.buttons_state = 0;
+
+    var msg = new Messages.SpiceMiniData();
+    msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_PRESS, press);
+    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+        this.sc.inputs.send_msg(msg);
+
+    msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_RELEASE, release);
+    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+        this.sc.inputs.send_msg(msg);
+
+    e.preventDefault();
+}
+
+function handle_keydown(e)
+{
+    var key = new Messages.SpiceMsgcKeyDown(e)
+    var msg = new Messages.SpiceMiniData();
+    check_and_update_modifiers(e, key.code, this.sc);
+    msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_DOWN, key);
+    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+        this.sc.inputs.send_msg(msg);
+
+    e.preventDefault();
+}
+
+function handle_keyup(e)
+{
+    var key = new Messages.SpiceMsgcKeyUp(e)
+    var msg = new Messages.SpiceMiniData();
+    check_and_update_modifiers(e, key.code, this.sc);
+    msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_UP, key);
+    if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready")
+        this.sc.inputs.send_msg(msg);
+
+    e.preventDefault();
+}
+
+function sendCtrlAltDel()
+{
+    if (sc && sc.inputs && sc.inputs.state === "ready"){
+        var key = new Messages.SpiceMsgcKeyDown();
+        var msg = new Messages.SpiceMiniData();
+
+        update_modifier(true, KeyNames.KEY_LCtrl, sc);
+        update_modifier(true, KeyNames.KEY_Alt, sc);
+
+        key.code = KeyNames.KEY_KP_Decimal;
+        msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_DOWN, key);
+        sc.inputs.send_msg(msg);
+        msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_UP, key);
+        sc.inputs.send_msg(msg);
+
+        if(Ctrl_state == false) update_modifier(false, KeyNames.KEY_LCtrl, sc);
+        if(Alt_state == false) update_modifier(false, KeyNames.KEY_Alt, sc);
+    }
+}
+
+function update_modifier(state, code, sc)
+{
+    var msg = new Messages.SpiceMiniData();
+    if (!state)
+    {
+        var key = new Messages.SpiceMsgcKeyUp()
+        key.code =(0x80|code);
+        msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_UP, key);
+    }
+    else
+    {
+        var key = new Messages.SpiceMsgcKeyDown()
+        key.code = code;
+        msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_DOWN, key);
+    }
+
+    sc.inputs.send_msg(msg);
+}
+
+function check_and_update_modifiers(e, code, sc)
+{
+    if (Shift_state === -1)
+    {
+        Shift_state = e.shiftKey;
+        Ctrl_state = e.ctrlKey;
+        Alt_state = e.altKey;
+        Meta_state = e.metaKey;
+    }
+
+    if (code === KeyNames.KEY_ShiftL)
+        Shift_state = true;
+    else if (code === KeyNames.KEY_Alt)
+        Alt_state = true;
+    else if (code === KeyNames.KEY_LCtrl)
+        Ctrl_state = true;
+    else if (code === 0xE0B5)
+        Meta_state = true;
+    else if (code === (0x80|KeyNames.KEY_ShiftL))
+        Shift_state = false;
+    else if (code === (0x80|KeyNames.KEY_Alt))
+        Alt_state = false;
+    else if (code === (0x80|KeyNames.KEY_LCtrl))
+        Ctrl_state = false;
+    else if (code === (0x80|0xE0B5))
+        Meta_state = false;
+
+    if (sc && sc.inputs && sc.inputs.state === "ready")
+    {
+        if (Shift_state != e.shiftKey)
+        {
+            console.log("Shift state out of sync");
+            update_modifier(e.shiftKey, KeyNames.KEY_ShiftL, sc);
+            Shift_state = e.shiftKey;
+        }
+        if (Alt_state != e.altKey)
+        {
+            console.log("Alt state out of sync");
+            update_modifier(e.altKey, KeyNames.KEY_Alt, sc);
+            Alt_state = e.altKey;
+        }
+        if (Ctrl_state != e.ctrlKey)
+        {
+            console.log("Ctrl state out of sync");
+            update_modifier(e.ctrlKey, KeyNames.KEY_LCtrl, sc);
+            Ctrl_state = e.ctrlKey;
+        }
+        if (Meta_state != e.metaKey)
+        {
+            console.log("Meta state out of sync");
+            update_modifier(e.metaKey, 0xE0B5, sc);
+            Meta_state = e.metaKey;
+        }
+    }
+}
+
+export {
+  SpiceInputsConn,
+  handle_mousemove,
+  handle_mousedown,
+  handle_contextmenu,
+  handle_mouseup,
+  handle_mousewheel,
+  handle_keydown,
+  handle_keyup,
+  sendCtrlAltDel,
+};
diff -pruN 0.1.7-5/src/lz.js 0.2.2-0ubuntu3/src/lz.js
--- 0.1.7-5/src/lz.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/lz.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,188 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import { Constants } from './enums.js';
+
+/*----------------------------------------------------------------------------
+**  lz.js
+**      Functions for handling SPICE_IMAGE_TYPE_LZ_RGB
+**  Adapted from lz.c .
+**--------------------------------------------------------------------------*/
+function lz_rgb32_decompress(in_buf, at, out_buf, type, default_alpha)
+{
+    var encoder = at;
+    var op = 0;
+    var ctrl;
+    var ctr = 0;
+    var i = 0;
+
+    for (ctrl = in_buf[encoder++]; (op * 4) < out_buf.length; ctrl = in_buf[encoder++])
+    {
+        var ref = op;
+        var len = ctrl >> 5;
+        var ofs = (ctrl & 31) << 8;
+
+//if (type == LZ_IMAGE_TYPE_RGBA)
+//console.log(ctr++ + ": from " + (encoder + 28) + ", ctrl " + ctrl + ", len " + len + ", ofs " + ofs + ", op " + op);
+        if (ctrl >= 32) {
+
+            var code;
+            len--;
+
+            if (len == 7 - 1) {
+                do {
+                    code = in_buf[encoder++];
+                    len += code;
+                } while (code == 255);
+            }
+            code = in_buf[encoder++];
+            ofs += code;
+
+
+            if (code == 255) {
+                if ((ofs - code) == (31 << 8)) {
+                    ofs = in_buf[encoder++] << 8;
+                    ofs += in_buf[encoder++];
+                    ofs += 8191;
+                }
+            }
+            len += 1;
+            if (type == Constants.LZ_IMAGE_TYPE_RGBA)
+                len += 2;
+
+            ofs += 1;
+
+            ref -= ofs;
+            if (ref == (op - 1)) {
+                var b = ref;
+//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha " + out_buf[(b*4)+3] + " dupped into pixel " + op + " through pixel " + (op + len));
+                for (; len; --len) {
+                    if (type == Constants.LZ_IMAGE_TYPE_RGBA)
+                    {
+                        out_buf[(op*4) + 3] = out_buf[(b*4)+3];
+                    }
+                    else
+                    {
+                        for (i = 0; i < 4; i++)
+                            out_buf[(op*4) + i] = out_buf[(b*4)+i];
+                    }
+                    op++;
+                }
+            } else {
+//if (type == LZ_IMAGE_TYPE_RGBA) console.log("alpha copied to pixel " + op + " through " + (op + len) + " from " + ref);
+                for (; len; --len) {
+                    if (type == Constants.LZ_IMAGE_TYPE_RGBA)
+                    {
+                        out_buf[(op*4) + 3] = out_buf[(ref*4)+3];
+                    }
+                    else
+                    {
+                        for (i = 0; i < 4; i++)
+                            out_buf[(op*4) + i] = out_buf[(ref*4)+i];
+                    }
+                    op++; ref++;
+                }
+            }
+        } else {
+            ctrl++;
+
+            if (type == Constants.LZ_IMAGE_TYPE_RGBA)
+            {
+//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
+                out_buf[(op*4) + 3] = in_buf[encoder++];
+            }
+            else
+            {
+                out_buf[(op*4) + 0] = in_buf[encoder + 2];
+                out_buf[(op*4) + 1] = in_buf[encoder + 1];
+                out_buf[(op*4) + 2] = in_buf[encoder + 0];
+                if (default_alpha)
+                    out_buf[(op*4) + 3] = 255;
+                encoder += 3;
+            }
+            op++;
+
+
+            for (--ctrl; ctrl; ctrl--) {
+                if (type == Constants.LZ_IMAGE_TYPE_RGBA)
+                {
+//console.log("alpha " + in_buf[encoder] + " set into pixel " + op);
+                    out_buf[(op*4) + 3] = in_buf[encoder++];
+                }
+                else
+                {
+                    out_buf[(op*4) + 0] = in_buf[encoder + 2];
+                    out_buf[(op*4) + 1] = in_buf[encoder + 1];
+                    out_buf[(op*4) + 2] = in_buf[encoder + 0];
+                    if (default_alpha)
+                        out_buf[(op*4) + 3] = 255;
+                    encoder += 3;
+                }
+                op++;
+            }
+        }
+
+    }
+    return encoder - 1;
+}
+
+function flip_image_data(img)
+{
+    var wb = img.width * 4;
+    var h = img.height;
+    var temp_h = h;
+    var buff = new Uint8Array(img.width * img.height * 4);
+    while (temp_h--)
+    {
+        buff.set(img.data.subarray(temp_h * wb, (temp_h + 1) * wb), (h - temp_h - 1) * wb);
+    }
+    img.data.set(buff);
+}
+
+function convert_spice_lz_to_web(context, lz_image)
+{
+    var at;
+    if (lz_image.type === Constants.LZ_IMAGE_TYPE_RGB32 || lz_image.type === Constants.LZ_IMAGE_TYPE_RGBA)
+    {
+        var u8 = new Uint8Array(lz_image.data);
+        var ret = context.createImageData(lz_image.width, lz_image.height);
+
+        at = lz_rgb32_decompress(u8, 0, ret.data, Constants.LZ_IMAGE_TYPE_RGB32, lz_image.type != Constants.LZ_IMAGE_TYPE_RGBA);
+        if (!lz_image.top_down)
+            flip_image_data(ret);
+
+        if (lz_image.type == Constants.LZ_IMAGE_TYPE_RGBA)
+            lz_rgb32_decompress(u8, at, ret.data, Constants.LZ_IMAGE_TYPE_RGBA, false);
+    }
+    else if (lz_image.type === Constants.LZ_IMAGE_TYPE_XXXA)
+    {
+        var u8 = new Uint8Array(lz_image.data);
+        var ret = context.createImageData(lz_image.width, lz_image.height);
+        lz_rgb32_decompress(u8, 0, ret.data, Constants.LZ_IMAGE_TYPE_RGBA, false);
+    }
+    else
+        return undefined;
+
+    return ret;
+}
+
+export {
+  convert_spice_lz_to_web,
+};
diff -pruN 0.1.7-5/src/main.js 0.2.2-0ubuntu3/src/main.js
--- 0.1.7-5/src/main.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/main.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,519 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import * as Messages from './spicemsg.js';
+import { Constants } from './enums.js';
+import { SpiceCursorConn } from './cursor.js';
+import { SpiceConn } from './spiceconn.js';
+import { DEBUG } from './utils.js';
+import { SpiceFileXferTask } from './filexfer.js';
+import { SpiceInputsConn, sendCtrlAltDel } from './inputs.js';
+import { SpiceDisplayConn } from './display.js';
+import { SpicePlaybackConn } from './playback.js';
+import { SpicePortConn } from './port.js';
+import { handle_file_dragover, handle_file_drop } from './filexfer.js';
+import { resize_helper, handle_resize } from './resize.js';
+
+/*----------------------------------------------------------------------------
+**  SpiceMainConn
+**      This is the master Javascript class for establishing and
+**  managing a connection to a Spice Server.
+**
+**      Invocation:  You must pass an object with properties as follows:
+**          uri         (required)  Uri of a WebSocket listener that is
+**                                  connected to a spice server.
+**          password    (required)  Password to send to the spice server
+**          message_id  (optional)  Identifier of an element in the DOM
+**                                  where SpiceConn will write messages.
+**                                  It will use classes spice-messages-x,
+**                                  where x is one of info, warning, or error.
+**          screen_id   (optional)  Identifier of an element in the DOM
+**                                  where SpiceConn will create any new
+**                                  client screens.  This is the main UI.
+**          dump_id     (optional)  If given, an element to use for
+**                                  dumping every single image + canvas drawn.
+**                                  Sometimes useful for debugging.
+**          onerror     (optional)  If given, a function to receive async
+**                                  errors.  Note that you should also catch
+**                                  errors for ones that occur inline
+**          onagent     (optional)  If given, a function to be called when
+**                                  a VD agent is connected; a good opportunity
+**                                  to request a resize
+**          onsuccess   (optional)  If given, a function to be called when the
+**                                  session is successfully connected
+**
+**  Throws error if there are troubles.  Requires a modern (by 2012 standards)
+**      browser, including WebSocket and WebSocket.binaryType == arraybuffer
+**
+**--------------------------------------------------------------------------*/
+function SpiceMainConn()
+{
+    if (typeof WebSocket === "undefined")
+        throw new Error("WebSocket unavailable.  You need to use a different browser.");
+
+    SpiceConn.apply(this, arguments);
+
+    this.agent_msg_queue = [];
+    this.file_xfer_tasks = {};
+    this.file_xfer_task_id = 0;
+    this.file_xfer_read_queue = [];
+    this.ports = [];
+}
+
+SpiceMainConn.prototype = Object.create(SpiceConn.prototype);
+SpiceMainConn.prototype.process_channel_message = function(msg)
+{
+    if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_BEGIN)
+    {
+        this.known_unimplemented(msg.type, "Main Migrate Begin");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_CANCEL)
+    {
+        this.known_unimplemented(msg.type, "Main Migrate Cancel");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_INIT)
+    {
+        this.log_info("Connected to " + this.ws.url);
+        this.report_success("Connected")
+        this.main_init = new Messages.SpiceMsgMainInit(msg.data);
+        this.connection_id = this.main_init.session_id;
+        this.agent_tokens = this.main_init.agent_tokens;
+
+        if (DEBUG > 0)
+        {
+            // FIXME - there is a lot here we don't handle; mouse modes, agent,
+            //          ram_hint, multi_media_time
+            this.log_info("session id "                 + this.main_init.session_id +
+                          " ; display_channels_hint "   + this.main_init.display_channels_hint +
+                          " ; supported_mouse_modes "   + this.main_init.supported_mouse_modes +
+                          " ; current_mouse_mode "      + this.main_init.current_mouse_mode +
+                          " ; agent_connected "         + this.main_init.agent_connected +
+                          " ; agent_tokens "            + this.main_init.agent_tokens +
+                          " ; multi_media_time "        + this.main_init.multi_media_time +
+                          " ; ram_hint "                + this.main_init.ram_hint);
+        }
+
+        this.our_mm_time = Date.now();
+        this.mm_time = this.main_init.multi_media_time;
+
+        this.handle_mouse_mode(this.main_init.current_mouse_mode,
+                               this.main_init.supported_mouse_modes);
+
+        if (this.main_init.agent_connected)
+            this.connect_agent();
+
+        var attach = new Messages.SpiceMiniData;
+        attach.type = Constants.SPICE_MSGC_MAIN_ATTACH_CHANNELS;
+        attach.size = attach.buffer_size();
+        this.send_msg(attach);
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MOUSE_MODE)
+    {
+        var mode = new Messages.SpiceMsgMainMouseMode(msg.data);
+        DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode);
+        this.handle_mouse_mode(mode.current_mode, mode.supported_modes);
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MULTI_MEDIA_TIME)
+    {
+        this.known_unimplemented(msg.type, "Main Multi Media Time");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_CHANNELS_LIST)
+    {
+        var i;
+        var chans;
+        DEBUG > 0 && console.log("channels");
+        chans = new Messages.SpiceMsgChannels(msg.data);
+        for (i = 0; i < chans.channels.length; i++)
+        {
+            var conn = {
+                        uri: this.ws.url,
+                        parent: this,
+                        connection_id : this.connection_id,
+                        type : chans.channels[i].type,
+                        chan_id : chans.channels[i].id
+                    };
+            if (chans.channels[i].type == Constants.SPICE_CHANNEL_DISPLAY)
+            {
+                if (chans.channels[i].id == 0) {
+                    this.display = new SpiceDisplayConn(conn);
+                } else {
+                    this.log_warn("The spice-html5 client does not handle multiple heads.");
+                }
+            }
+            else if (chans.channels[i].type == Constants.SPICE_CHANNEL_INPUTS)
+            {
+                this.inputs = new SpiceInputsConn(conn);
+                this.inputs.mouse_mode = this.mouse_mode;
+            }
+            else if (chans.channels[i].type == Constants.SPICE_CHANNEL_CURSOR)
+                this.cursor = new SpiceCursorConn(conn);
+            else if (chans.channels[i].type == Constants.SPICE_CHANNEL_PLAYBACK)
+                this.cursor = new SpicePlaybackConn(conn);
+            else if (chans.channels[i].type == Constants.SPICE_CHANNEL_PORT)
+                this.ports.push(new SpicePortConn(conn));
+            else
+            {
+                if (! ("extra_channels" in this))
+                    this.extra_channels = [];
+                this.extra_channels[i] = new SpiceConn(conn);
+                this.log_err("Channel type " + this.extra_channels[i].channel_type() + " not implemented");
+            }
+
+        }
+
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_CONNECTED)
+    {
+        this.connect_agent();
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS)
+    {
+        var connected_tokens = new Messages.SpiceMsgMainAgentTokens(msg.data);
+        this.agent_tokens = connected_tokens.num_tokens;
+        this.connect_agent();
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_TOKEN)
+    {
+        var remaining_tokens, tokens = new Messages.SpiceMsgMainAgentTokens(msg.data);
+        this.agent_tokens += tokens.num_tokens;
+        this.send_agent_message_queue();
+
+        remaining_tokens = this.agent_tokens;
+        while (remaining_tokens > 0 && this.file_xfer_read_queue.length > 0)
+        {
+            var xfer_task = this.file_xfer_read_queue.shift();
+            this.file_xfer_read(xfer_task, xfer_task.read_bytes);
+            remaining_tokens--;
+        }
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_DISCONNECTED)
+    {
+        this.agent_connected = false;
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_DATA)
+    {
+        var agent_data = new Messages.SpiceMsgMainAgentData(msg.data);
+        if (agent_data.type == Constants.VD_AGENT_ANNOUNCE_CAPABILITIES)
+        {
+            var agent_caps = new Messages.VDAgentAnnounceCapabilities(agent_data.data);
+            if (agent_caps.request)
+                this.announce_agent_capabilities(0);
+            return true;
+        }
+        else if (agent_data.type == Constants.VD_AGENT_FILE_XFER_STATUS)
+        {
+            this.handle_file_xfer_status(new Messages.VDAgentFileXferStatusMessage(agent_data.data));
+            return true;
+        }
+
+        return false;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST)
+    {
+        this.known_unimplemented(msg.type, "Main Migrate Switch Host");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_END)
+    {
+        this.known_unimplemented(msg.type, "Main Migrate End");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_NAME)
+    {
+        this.known_unimplemented(msg.type, "Main Name");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_UUID)
+    {
+        this.known_unimplemented(msg.type, "Main UUID");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS)
+    {
+        this.known_unimplemented(msg.type, "Main Migrate Begin Seamless");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK)
+    {
+        this.known_unimplemented(msg.type, "Main Migrate Dst Seamless ACK");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK)
+    {
+        this.known_unimplemented(msg.type, "Main Migrate Dst Seamless NACK");
+        return true;
+    }
+
+    return false;
+}
+
+SpiceMainConn.prototype.stop = function(msg)
+{
+    this.state = "closing";
+
+    if (this.inputs)
+    {
+        this.inputs.cleanup();
+        this.inputs = undefined;
+    }
+
+    if (this.cursor)
+    {
+        this.cursor.cleanup();
+        this.cursor = undefined;
+    }
+
+    if (this.display)
+    {
+        this.display.cleanup();
+        this.display.destroy_surfaces();
+        this.display = undefined;
+    }
+
+    this.cleanup();
+
+    if ("extra_channels" in this)
+        for (var e in this.extra_channels)
+            this.extra_channels[e].cleanup();
+    this.extra_channels = undefined;
+}
+
+SpiceMainConn.prototype.send_agent_message_queue = function(message)
+{
+    if (!this.agent_connected)
+        return;
+
+    if (message)
+        this.agent_msg_queue.push(message);
+
+    while (this.agent_tokens > 0 && this.agent_msg_queue.length > 0)
+    {
+        var mr = this.agent_msg_queue.shift();
+        this.send_msg(mr);
+        this.agent_tokens--;
+    }
+}
+
+SpiceMainConn.prototype.send_agent_message = function(type, message)
+{
+    var agent_data = new Messages.SpiceMsgcMainAgentData(type, message);
+    var sb = 0, maxsize = Constants.VD_AGENT_MAX_DATA_SIZE - Messages.SpiceMiniData.prototype.buffer_size();
+    var data = new ArrayBuffer(agent_data.buffer_size());
+    agent_data.to_buffer(data);
+    while (sb < agent_data.buffer_size())
+    {
+        var eb = Math.min(sb + maxsize, agent_data.buffer_size());
+        var mr = new Messages.SpiceMiniData();
+        mr.type = Constants.SPICE_MSGC_MAIN_AGENT_DATA;
+        mr.size = eb - sb;
+        mr.data = data.slice(sb, eb);
+        this.send_agent_message_queue(mr);
+        sb = eb;
+    }
+}
+
+SpiceMainConn.prototype.announce_agent_capabilities = function(request)
+{
+    var caps = new Messages.VDAgentAnnounceCapabilities(request, (1 << Constants.VD_AGENT_CAP_MOUSE_STATE) |
+                                                        (1 << Constants.VD_AGENT_CAP_MONITORS_CONFIG) |
+                                                        (1 << Constants.VD_AGENT_CAP_REPLY));
+    this.send_agent_message(Constants.VD_AGENT_ANNOUNCE_CAPABILITIES, caps);
+}
+
+SpiceMainConn.prototype.resize_window = function(flags, width, height, depth, x, y)
+{
+    var monitors_config = new Messages.VDAgentMonitorsConfig(flags, width, height, depth, x, y);
+    this.send_agent_message(Constants.VD_AGENT_MONITORS_CONFIG, monitors_config);
+}
+
+SpiceMainConn.prototype.file_xfer_start = function(file)
+{
+    var task_id, xfer_start, task;
+
+    task_id = this.file_xfer_task_id++;
+    task = new SpiceFileXferTask(task_id, file);
+    task.create_progressbar();
+    this.file_xfer_tasks[task_id] = task;
+    xfer_start = new Messages.VDAgentFileXferStartMessage(task_id, file.name, file.size);
+    this.send_agent_message(Constants.VD_AGENT_FILE_XFER_START, xfer_start);
+}
+
+SpiceMainConn.prototype.handle_file_xfer_status = function(file_xfer_status)
+{
+    var xfer_error, xfer_task;
+    if (!this.file_xfer_tasks[file_xfer_status.id])
+    {
+        return;
+    }
+    xfer_task = this.file_xfer_tasks[file_xfer_status.id];
+    switch (file_xfer_status.result)
+    {
+        case Constants.VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA:
+            this.file_xfer_read(xfer_task);
+            return;
+        case Constants.VD_AGENT_FILE_XFER_STATUS_CANCELLED:
+            xfer_error = "transfer is cancelled by spice agent";
+            break;
+        case Constants.VD_AGENT_FILE_XFER_STATUS_ERROR:
+            xfer_error = "some errors occurred in the spice agent";
+            break;
+        case Constants.VD_AGENT_FILE_XFER_STATUS_SUCCESS:
+            break;
+        default:
+            xfer_error = "unhandled status type: " + file_xfer_status.result;
+            break;
+    }
+
+    this.file_xfer_completed(xfer_task, xfer_error)
+}
+
+SpiceMainConn.prototype.file_xfer_read = function(file_xfer_task, start_byte)
+{
+    var FILE_XFER_CHUNK_SIZE = 32 * Constants.VD_AGENT_MAX_DATA_SIZE;
+    var _this = this;
+    var sb, eb;
+    var slice, reader;
+
+    if (!file_xfer_task ||
+        !this.file_xfer_tasks[file_xfer_task.id] ||
+        (start_byte > 0 && start_byte == file_xfer_task.file.size))
+    {
+        return;
+    }
+
+    if (file_xfer_task.cancelled)
+    {
+        var xfer_status = new Messages.VDAgentFileXferStatusMessage(file_xfer_task.id,
+                                                           Constants.VD_AGENT_FILE_XFER_STATUS_CANCELLED);
+        this.send_agent_message(Constants.VD_AGENT_FILE_XFER_STATUS, xfer_status);
+        delete this.file_xfer_tasks[file_xfer_task.id];
+        return;
+    }
+
+    sb = start_byte || 0,
+    eb = Math.min(sb + FILE_XFER_CHUNK_SIZE, file_xfer_task.file.size);
+
+    if (!this.agent_tokens)
+    {
+        file_xfer_task.read_bytes = sb;
+        this.file_xfer_read_queue.push(file_xfer_task);
+        return;
+    }
+
+    reader = new FileReader();
+    reader.onload = function(e)
+    {
+        var xfer_data = new Messages.VDAgentFileXferDataMessage(file_xfer_task.id,
+                                                       e.target.result.byteLength,
+                                                       e.target.result);
+        _this.send_agent_message(Constants.VD_AGENT_FILE_XFER_DATA, xfer_data);
+        _this.file_xfer_read(file_xfer_task, eb);
+        file_xfer_task.update_progressbar(eb);
+    };
+
+    slice = file_xfer_task.file.slice(sb, eb);
+    reader.readAsArrayBuffer(slice);
+}
+
+SpiceMainConn.prototype.file_xfer_completed = function(file_xfer_task, error)
+{
+    if (error)
+        this.log_err(error);
+    else
+        this.log_info("transfer of '" + file_xfer_task.file.name +"' was successful");
+
+    file_xfer_task.remove_progressbar();
+
+    delete this.file_xfer_tasks[file_xfer_task.id];
+}
+
+SpiceMainConn.prototype.connect_agent = function()
+{
+    this.agent_connected = true;
+
+    var agent_start = new Messages.SpiceMsgcMainAgentStart(~0);
+    var mr = new Messages.SpiceMiniData();
+    mr.build_msg(Constants.SPICE_MSGC_MAIN_AGENT_START, agent_start);
+    this.send_msg(mr);
+
+    this.announce_agent_capabilities(1);
+
+    if (this.onagent !== undefined)
+        this.onagent(this);
+
+}
+
+SpiceMainConn.prototype.handle_mouse_mode = function(current, supported)
+{
+    this.mouse_mode = current;
+    if (current != Constants.SPICE_MOUSE_MODE_CLIENT && (supported & Constants.SPICE_MOUSE_MODE_CLIENT))
+    {
+        var mode_request = new Messages.SpiceMsgcMainMouseModeRequest(Constants.SPICE_MOUSE_MODE_CLIENT);
+        var mr = new Messages.SpiceMiniData();
+        mr.build_msg(Constants.SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request);
+        this.send_msg(mr);
+    }
+
+    if (this.inputs)
+        this.inputs.mouse_mode = current;
+}
+
+/* Shift current time to attempt to get a time matching that of the server */
+SpiceMainConn.prototype.relative_now = function()
+{
+    var ret = (Date.now() - this.our_mm_time) + this.mm_time;
+    return ret;
+}
+
+export {
+  SpiceMainConn,
+  handle_file_dragover,
+  handle_file_drop,
+  resize_helper,
+  handle_resize,
+  sendCtrlAltDel,
+};
diff -pruN 0.1.7-5/src/playback.js 0.2.2-0ubuntu3/src/playback.js
--- 0.1.7-5/src/playback.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/playback.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,409 @@
+"use strict";
+/*
+   Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  SpicePlaybackConn
+**      Drive the Spice Playback channel (sound out)
+**--------------------------------------------------------------------------*/
+
+import * as Utils from './utils.js';
+import * as Webm from './webm.js';
+import * as Messages from './spicemsg.js';
+import { Constants } from './enums.js';
+import { SpiceConn } from './spiceconn.js';
+
+function SpicePlaybackConn()
+{
+    SpiceConn.apply(this, arguments);
+
+    this.queue = new Array();
+    this.append_okay = false;
+    this.start_time = 0;
+}
+
+SpicePlaybackConn.prototype = Object.create(SpiceConn.prototype);
+SpicePlaybackConn.prototype.process_channel_message = function(msg)
+{
+    if (!!!window.MediaSource)
+    {
+        this.log_err('MediaSource API is not available');
+        return false;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_PLAYBACK_START)
+    {
+        var start = new Messages.SpiceMsgPlaybackStart(msg.data);
+
+        Utils.PLAYBACK_DEBUG > 0 && console.log("PlaybackStart; frequency " + start.frequency);
+
+        if (start.frequency != Webm.Constants.OPUS_FREQUENCY)
+        {
+            this.log_err('This player cannot handle frequency ' + start.frequency);
+            return false;
+        }
+
+        if (start.channels != Webm.Constants.OPUS_CHANNELS)
+        {
+            this.log_err('This player cannot handle ' + start.channels + ' channels');
+            return false;
+        }
+
+        if (start.format != Constants.SPICE_AUDIO_FMT_S16)
+        {
+            this.log_err('This player cannot format ' + start.format);
+            return false;
+        }
+
+        if (! this.source_buffer)
+        {
+            this.media_source = new MediaSource();
+            this.media_source.spiceconn = this;
+
+            this.audio = document.createElement("audio");
+            this.audio.spiceconn = this;
+            this.audio.setAttribute('autoplay', true);
+            this.audio.src = window.URL.createObjectURL(this.media_source);
+            document.getElementById(this.parent.screen_id).appendChild(this.audio);
+
+            this.media_source.addEventListener('sourceopen', handle_source_open, false);
+            this.media_source.addEventListener('sourceended', handle_source_ended, false);
+            this.media_source.addEventListener('sourceclosed', handle_source_closed, false);
+
+            this.bytes_written = 0;
+
+            return true;
+        }
+    }
+
+    if (msg.type == Constants.SPICE_MSG_PLAYBACK_DATA)
+    {
+        var data = new Messages.SpiceMsgPlaybackData(msg.data);
+
+        if (! this.source_buffer)
+            return true;
+
+        if (this.audio.readyState >= 3 && this.audio.buffered.length > 1 &&
+            this.audio.currentTime == this.audio.buffered.end(0) &&
+            this.audio.currentTime < this.audio.buffered.start(this.audio.buffered.length - 1))
+        {
+            console.log("Audio underrun: we appear to have fallen behind; advancing to " +
+                this.audio.buffered.start(this.audio.buffered.length - 1));
+            this.audio.currentTime = this.audio.buffered.start(this.audio.buffered.length - 1);
+        }
+
+        /* Around version 45, Firefox started being very particular about the
+           time stamps put into the Opus stream.  The time stamps from the Spice server are
+           somewhat irregular.  They mostly arrive every 10 ms, but sometimes it is 11, or sometimes
+           with two time stamps the same in a row.  The previous logic resulted in fuzzy and/or
+           distorted audio streams in Firefox in a row.
+
+           In theory, the sequence mode should be appropriate for us, but as of 09/27/2016,
+           I was unable to make sequence mode work with Firefox.
+
+           Thus, we end up with an inelegant hack.  Essentially, we force every packet to have
+           a 10ms time delta, unless there is an obvious gap in time stream, in which case we
+           will resync.
+        */
+
+        if (this.start_time != 0 && data.time != (this.last_data_time + Webm.Constants.EXPECTED_PACKET_DURATION))
+        {
+            if (Math.abs(data.time - (Webm.Constants.EXPECTED_PACKET_DURATION + this.last_data_time)) < Webm.Constants.MAX_CLUSTER_TIME)
+            {
+                Utils.PLAYBACK_DEBUG > 1 && console.log("Hacking time of " + data.time + " to " +
+                                      (this.last_data_time + Webm.Constants.EXPECTED_PACKET_DURATION));
+                data.time = this.last_data_time + Webm.Constants.EXPECTED_PACKET_DURATION;
+            }
+            else
+            {
+                Utils.PLAYBACK_DEBUG > 1 && console.log("Apparent gap in audio time; now is " + data.time + " last was " + this.last_data_time);
+            }
+        }
+
+        this.last_data_time = data.time;
+
+        Utils.PLAYBACK_DEBUG > 1 && console.log("PlaybackData; time " + data.time + "; length " + data.data.byteLength);
+
+        if (this.start_time == 0)
+            this.start_playback(data);
+
+        else if (data.time - this.cluster_time >= Webm.Constants.MAX_CLUSTER_TIME)
+            this.new_cluster(data);
+
+        else
+            this.simple_block(data, false);
+
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_PLAYBACK_MODE)
+    {
+        var mode = new Messages.SpiceMsgPlaybackMode(msg.data);
+        if (mode.mode != Constants.SPICE_AUDIO_DATA_MODE_OPUS)
+        {
+            this.log_err('This player cannot handle mode ' + mode.mode);
+            delete this.source_buffer;
+        }
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_PLAYBACK_STOP)
+    {
+        Utils.PLAYBACK_DEBUG > 0 && console.log("PlaybackStop");
+        if (this.source_buffer)
+        {
+            document.getElementById(this.parent.screen_id).removeChild(this.audio);
+            window.URL.revokeObjectURL(this.audio.src);
+
+            delete this.source_buffer;
+            delete this.media_source;
+            delete this.audio;
+
+            this.append_okay = false;
+            this.queue = new Array();
+            this.start_time = 0;
+
+            return true;
+        }
+    }
+
+    if (msg.type == Constants.SPICE_MSG_PLAYBACK_VOLUME)
+    {
+        this.known_unimplemented(msg.type, "Playback Volume");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_PLAYBACK_MUTE)
+    {
+        this.known_unimplemented(msg.type, "Playback Mute");
+        return true;
+    }
+
+    if (msg.type == Constants.SPICE_MSG_PLAYBACK_LATENCY)
+    {
+        this.known_unimplemented(msg.type, "Playback Latency");
+        return true;
+    }
+
+    return false;
+}
+
+SpicePlaybackConn.prototype.start_playback = function(data)
+{
+    this.start_time = data.time;
+
+    var h = new Webm.Header();
+    var te = new Webm.AudioTrackEntry;
+    var t = new Webm.Tracks(te);
+
+    var mb = new ArrayBuffer(h.buffer_size() + t.buffer_size())
+
+    this.bytes_written = h.to_buffer(mb);
+    this.bytes_written = t.to_buffer(mb, this.bytes_written);
+
+    this.source_buffer.addEventListener('error', handle_sourcebuffer_error, false);
+    this.source_buffer.addEventListener('updateend', handle_append_buffer_done, false);
+    playback_append_buffer(this, mb);
+
+    this.new_cluster(data);
+}
+
+SpicePlaybackConn.prototype.new_cluster = function(data)
+{
+    this.cluster_time = data.time;
+
+    var c = new Webm.Cluster(data.time - this.start_time);
+
+    var mb = new ArrayBuffer(c.buffer_size());
+    this.bytes_written += c.to_buffer(mb);
+
+    if (this.append_okay)
+        playback_append_buffer(this, mb);
+    else
+        this.queue.push(mb);
+
+    this.simple_block(data, true);
+}
+
+SpicePlaybackConn.prototype.simple_block = function(data, keyframe)
+{
+    var sb = new Webm.SimpleBlock(data.time - this.cluster_time, data.data, keyframe);
+    var mb = new ArrayBuffer(sb.buffer_size());
+
+    this.bytes_written += sb.to_buffer(mb);
+
+    if (this.append_okay)
+        playback_append_buffer(this, mb);
+    else
+        this.queue.push(mb);
+}
+
+function handle_source_open(e)
+{
+    var p = this.spiceconn;
+
+    if (p.source_buffer)
+        return;
+
+    p.source_buffer = this.addSourceBuffer(Webm.Constants.SPICE_PLAYBACK_CODEC);
+    if (! p.source_buffer)
+    {
+        p.log_err('Codec ' + Webm.Constants.SPICE_PLAYBACK_CODEC + ' not available.');
+        return;
+    }
+
+    if (Utils.PLAYBACK_DEBUG > 0)
+        playback_handle_event_debug.call(this, e);
+
+    listen_for_audio_events(p);
+
+    p.source_buffer.spiceconn = p;
+    p.source_buffer.mode = "segments";
+
+    // FIXME - Experimentation with segments and sequences was unsatisfying.
+    //         Switching to sequence did not solve our gap problem,
+    //         but the browsers didn't fully support the time seek capability
+    //         we would expect to gain from 'segments'.
+    //         Segments worked at the time of this patch, so segments it is for now.
+
+}
+
+function handle_source_ended(e)
+{
+    var p = this.spiceconn;
+    p.log_err('Audio source unexpectedly ended.');
+}
+
+function handle_source_closed(e)
+{
+    var p = this.spiceconn;
+    p.log_err('Audio source unexpectedly closed.');
+}
+
+function condense_playback_queue(queue)
+{
+    if (queue.length == 1)
+        return queue.shift();
+
+    var len = 0;
+    var i = 0;
+    for (i = 0; i < queue.length; i++)
+        len += queue[i].byteLength;
+
+    var mb = new ArrayBuffer(len);
+    var tmp = new Uint8Array(mb);
+    len = 0;
+    for (i = 0; i < queue.length; i++)
+    {
+        tmp.set(new Uint8Array(queue[i]), len);
+        len += queue[i].byteLength;
+    }
+    queue.length = 0;
+    return mb;
+}
+
+function handle_append_buffer_done(e)
+{
+    var p = this.spiceconn;
+
+    if (Utils.PLAYBACK_DEBUG > 1)
+        playback_handle_event_debug.call(this, e);
+
+    if (p.queue.length > 0)
+    {
+        var mb = condense_playback_queue(p.queue);
+        playback_append_buffer(p, mb);
+    }
+    else
+        p.append_okay = true;
+
+}
+
+function handle_sourcebuffer_error(e)
+{
+    var p = this.spiceconn;
+    p.log_err('source_buffer error ' + e.message);
+}
+
+function playback_append_buffer(p, b)
+{
+    try
+    {
+        p.source_buffer.appendBuffer(b);
+        p.append_okay = false;
+    }
+    catch (e)
+    {
+        p.log_err("Error invoking appendBuffer: " + e.message);
+    }
+}
+
+function playback_handle_event_debug(e)
+{
+    var p = this.spiceconn;
+    if (p.audio)
+    {
+        if (Utils.PLAYBACK_DEBUG > 0 || p.audio.buffered.len > 1)
+            console.log(p.audio.currentTime + ": event " + e.type +
+                Utils.dump_media_element(p.audio));
+    }
+
+    if (Utils.PLAYBACK_DEBUG > 1 && p.media_source)
+        console.log("  media_source " + Utils.dump_media_source(p.media_source));
+
+    if (Utils.PLAYBACK_DEBUG > 1 && p.source_buffer)
+        console.log("  source_buffer " + Utils.dump_source_buffer(p.source_buffer));
+
+    if (Utils.PLAYBACK_DEBUG > 0 || p.queue.length > 1)
+        console.log('  queue len ' + p.queue.length + '; append_okay: ' + p.append_okay);
+}
+
+function playback_debug_listen_for_one_event(name)
+{
+    this.addEventListener(name, playback_handle_event_debug);
+}
+
+function listen_for_audio_events(spiceconn)
+{
+    var audio_0_events = [
+        "abort", "error"
+    ];
+
+    var audio_1_events = [
+        "loadstart", "suspend", "emptied", "stalled", "loadedmetadata", "loadeddata", "canplay",
+        "canplaythrough", "playing", "waiting", "seeking", "seeked", "ended", "durationchange",
+        "timeupdate", "play", "pause", "ratechange"
+    ];
+
+    var audio_2_events = [
+        "progress",
+        "resize",
+        "volumechange"
+    ];
+
+    audio_0_events.forEach(playback_debug_listen_for_one_event, spiceconn.audio);
+    if (Utils.PLAYBACK_DEBUG > 0)
+        audio_1_events.forEach(playback_debug_listen_for_one_event, spiceconn.audio);
+    if (Utils.PLAYBACK_DEBUG > 1)
+        audio_2_events.forEach(playback_debug_listen_for_one_event, spiceconn.audio);
+}
+
+export {
+  SpicePlaybackConn,
+};
diff -pruN 0.1.7-5/src/png.js 0.2.2-0ubuntu3/src/png.js
--- 0.1.7-5/src/png.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/png.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,262 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  crc logic from rfc2083 ported to Javascript
+**--------------------------------------------------------------------------*/
+
+import { SpiceDataView } from './spicedataview.js';
+
+var rfc2083_crc_table = Array(256);
+var rfc2083_crc_table_computed = 0;
+/* Make the table for a fast CRC. */
+function rfc2083_make_crc_table()
+{
+    var c;
+    var n, k;
+    for (n = 0; n < 256; n++)
+    {
+        c = n;
+        for (k = 0; k < 8; k++)
+        {
+            if (c & 1)
+                c = ((0xedb88320 ^ (c >>> 1)) >>> 0) & 0xffffffff;
+            else
+                c = c >>> 1;
+        }
+        rfc2083_crc_table[n] = c;
+    }
+
+    rfc2083_crc_table_computed = 1;
+}
+
+/* Update a running CRC with the bytes buf[0..len-1]--the CRC
+     should be initialized to all 1's, and the transmitted value
+     is the 1's complement of the final running CRC (see the
+     crc() routine below)). */
+
+function rfc2083_update_crc(crc, u8buf, at, len)
+{
+    var c = crc;
+    var n;
+
+    if (!rfc2083_crc_table_computed)
+        rfc2083_make_crc_table();
+
+    for (n = 0; n < len; n++)
+    {
+        c = rfc2083_crc_table[(c ^ u8buf[at + n]) & 0xff] ^ (c >>> 8);
+    }
+
+    return c;
+}
+
+function rfc2083_crc(u8buf, at, len)
+{
+    return rfc2083_update_crc(0xffffffff, u8buf, at, len) ^ 0xffffffff;
+}
+
+function crc32(mb, at, len)
+{
+    var u8 = new Uint8Array(mb);
+    return rfc2083_crc(u8, at, len);
+}
+
+function PngIHDR(width, height)
+{
+    this.width = width;
+    this.height = height;
+    this.depth = 8;
+    this.type = 6;
+    this.compression = 0;
+    this.filter = 0;
+    this.interlace = 0;
+}
+
+PngIHDR.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var orig = at;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.buffer_size() - 12); at += 4;
+        dv.setUint8(at, 'I'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'H'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'D'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'R'.charCodeAt(0)); at++;
+        dv.setUint32(at, this.width); at += 4;
+        dv.setUint32(at, this.height); at += 4;
+        dv.setUint8(at, this.depth); at++;
+        dv.setUint8(at, this.type); at++;
+        dv.setUint8(at, this.compression); at++;
+        dv.setUint8(at, this.filter); at++;
+        dv.setUint8(at, this.interlace); at++;
+        dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 12 + 13;
+    }
+}
+
+
+function adler()
+{
+    this.s1 = 1;
+    this.s2 = 0;
+}
+
+adler.prototype.update = function(b)
+{
+    this.s1 += b;
+    this.s1 %= 65521;
+    this.s2 += this.s1;
+    this.s2 %= 65521;
+}
+
+function PngIDAT(width, height, bytes)
+{
+    if (bytes.byteLength > 65535)
+    {
+        throw new Error("Cannot handle more than 64K");
+    }
+    this.data = bytes;
+    this.width = width;
+    this.height = height;
+}
+
+PngIDAT.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var orig = at;
+        var x, y, i, j;
+        var dv = new SpiceDataView(a);
+        var zsum = new adler();
+        dv.setUint32(at, this.buffer_size() - 12); at += 4;
+        dv.setUint8(at, 'I'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'D'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'A'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'T'.charCodeAt(0)); at++;
+
+        /* zlib header.  */
+        dv.setUint8(at, 0x78); at++;
+        dv.setUint8(at, 0x01); at++;
+
+        /* Deflate header.  Specifies uncompressed, final bit */
+        dv.setUint8(at, 0x80); at++;
+        dv.setUint16(at, this.data.byteLength + this.height); at += 2;
+        dv.setUint16(at, ~(this.data.byteLength + this.height)); at += 2;
+        var u8 = new Uint8Array(this.data);
+        for (i = 0, y = 0; y < this.height; y++)
+        {
+            /* Filter type 0 - uncompressed */
+            dv.setUint8(at, 0); at++;
+            zsum.update(0);
+            for (x = 0; x < this.width && i < this.data.byteLength; x++)
+            {
+                zsum.update(u8[i]);
+                dv.setUint8(at, u8[i++]); at++;
+                zsum.update(u8[i]);
+                dv.setUint8(at, u8[i++]); at++;
+                zsum.update(u8[i]);
+                dv.setUint8(at, u8[i++]); at++;
+                zsum.update(u8[i]);
+                dv.setUint8(at, u8[i++]); at++;
+            }
+        }
+
+        /* zlib checksum.   */
+        dv.setUint16(at, zsum.s2); at+=2;
+        dv.setUint16(at, zsum.s1); at+=2;
+
+        /* FIXME - something is not quite right with the zlib code;
+                   you get an error from libpng if you open the image in
+                   gimp.  But it works, so it's good enough for now... */
+
+        dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 12 + this.data.byteLength + this.height + 4 + 2 + 1 + 2 + 2;
+    }
+}
+
+
+function PngIEND()
+{
+}
+
+PngIEND.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var orig = at;
+        var i;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.buffer_size() - 12); at += 4;
+        dv.setUint8(at, 'I'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'E'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'N'.charCodeAt(0)); at++;
+        dv.setUint8(at, 'D'.charCodeAt(0)); at++;
+        dv.setUint32(at, crc32(a, orig + 4, this.buffer_size() - 8)); at += 4;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 12;
+    }
+}
+
+
+function create_rgba_png(width, height, bytes)
+{
+    var i;
+    var ihdr = new PngIHDR(width, height);
+    var idat = new PngIDAT(width, height, bytes);
+    var iend = new PngIEND;
+
+    var mb = new ArrayBuffer(ihdr.buffer_size() + idat.buffer_size() + iend.buffer_size());
+    var at = ihdr.to_buffer(mb);
+    at = idat.to_buffer(mb, at);
+    at = iend.to_buffer(mb, at);
+
+    var u8 = new Uint8Array(mb);
+    var str = "";
+    for (i = 0; i < at; i++)
+    {
+        str += "%";
+        if (u8[i] < 16)
+            str += "0";
+        str += u8[i].toString(16);
+    }
+
+
+    return "%89PNG%0D%0A%1A%0A" + str;
+}
+
+export {
+  create_rgba_png,
+};
diff -pruN 0.1.7-5/src/port.js 0.2.2-0ubuntu3/src/port.js
--- 0.1.7-5/src/port.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/port.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,94 @@
+"use strict";
+/*
+   Copyright (C) 2016 by Oliver Gutierrez <ogutsua@gmail.com>
+                         Miroslav Chodil <mchodil@redhat.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import { Constants } from './enums.js';
+import { DEBUG } from './utils.js';
+import { SpiceConn } from './spiceconn.js';
+import { SpiceMsgPortInit } from './spicemsg.js';
+
+/*----------------------------------------------------------------------------
+**  SpicePortConn
+**      Drive the Spice Port Channel
+**--------------------------------------------------------------------------*/
+function SpicePortConn()
+{
+    DEBUG > 0 && console.log('SPICE port: created SPICE port channel. Args:', arguments);
+    SpiceConn.apply(this, arguments);
+    this.port_name = null;
+}
+
+SpicePortConn.prototype = Object.create(SpiceConn.prototype);
+
+SpicePortConn.prototype.process_channel_message = function(msg)
+{
+    if (msg.type == Constants.SPICE_MSG_PORT_INIT)
+    {
+        if (this.port_name === null)
+        {
+            var m = new SpiceMsgPortInit(msg.data);
+            this.portName = arraybuffer_to_str(new Uint8Array(m.name));
+            this.portOpened = m.opened
+            DEBUG > 0 && console.log('SPICE port: Port', this.portName, 'initialized');
+            return true;
+        }
+
+        DEBUG > 0 && console.log('SPICE port: Port', this.port_name, 'is already initialized.');
+    }
+    else if (msg.type == Constants.SPICE_MSG_PORT_EVENT)
+    {
+        DEBUG > 0 && console.log('SPICE port: Port event received for', this.portName, msg);
+        var event = new CustomEvent('spice-port-event', {
+            detail: {
+                channel: this,
+                spiceEvent: new Uint8Array(msg.data)
+            },
+            bubbles: true,
+            cancelable: true
+        });
+
+        window.dispatchEvent(event);
+        return true;
+    }
+    else if (msg.type == Constants.SPICE_MSG_SPICEVMC_DATA)
+    {
+        DEBUG > 0 && console.log('SPICE port: Data received in port', this.portName, msg);
+        var event = new CustomEvent('spice-port-data', {
+            detail: {
+                channel: this,
+                data: msg.data
+            },
+            bubbles: true,
+            cancelable: true
+        });
+        window.dispatchEvent(event);
+        return true;
+    }
+    else
+    {
+        DEBUG > 0 && console.log('SPICE port: SPICE message type not recognized:', msg)
+    }
+
+    return false;
+};
+
+export {
+  SpicePortConn,
+};
diff -pruN 0.1.7-5/src/quic.js 0.2.2-0ubuntu3/src/quic.js
--- 0.1.7-5/src/quic.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/quic.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,1345 @@
+/*"use strict";*/
+/* use strict is commented out because it results in a 5x slowdone in chrome */
+/*
+ *    Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+ *    Copyright (C) 2012 by Aric Stewart <aric@codeweavers.com>
+ *
+ *    This file is part of spice-html5.
+ *
+ *    spice-html5 is free software: you can redistribute it and/or modify
+ *    it under the terms of the GNU Lesser General Public License as published by
+ *    the Free Software Foundation, either version 3 of the License, or
+ *    (at your option) any later version.
+ *
+ *    spice-html5 is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU Lesser General Public License for more details.
+ *
+ *    You should have received a copy of the GNU Lesser General Public License
+ *    along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var encoder;
+
+var Constants = {
+  QUIC_IMAGE_TYPE_INVALID : 0,
+  QUIC_IMAGE_TYPE_GRAY : 1,
+  QUIC_IMAGE_TYPE_RGB16 : 2,
+  QUIC_IMAGE_TYPE_RGB24 : 3,
+  QUIC_IMAGE_TYPE_RGB32 : 4,
+  QUIC_IMAGE_TYPE_RGBA : 5,
+};
+
+var DEFevol = 3;
+var DEFwmimax = 6;
+var DEFwminext = 2048;
+var need_init = true;
+var DEFmaxclen = 26;
+var evol = DEFevol;
+var wmimax = DEFwmimax;
+var wminext = DEFwminext;
+var family_5bpc = { nGRcodewords:[0,0,0,0,0,0,0,0],
+                    notGRcwlen:[0,0,0,0,0,0,0,0],
+                    notGRprefixmask:[0,0,0,0,0,0,0,0],
+                    notGRsuffixlen:[0,0,0,0,0,0,0,0],
+                    xlatU2L:[0,0,0,0,0,0,0,0],
+                    xlatL2U:[0,0,0,0,0,0,0,0]
+                  };
+var family_8bpc = { nGRcodewords:[0,0,0,0,0,0,0,0],
+                    notGRcwlen:[0,0,0,0,0,0,0,0],
+                    notGRprefixmask:[0,0,0,0,0,0,0,0],
+                    notGRsuffixlen:[0,0,0,0,0,0,0,0],
+                    xlatU2L:[0,0,0,0,0,0,0,0],
+                    xlatL2U:[0,0,0,0,0,0,0,0]
+                  };
+var bppmask = [ 0x00000000,
+    0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+    0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+    0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+    0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+    0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+    0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+    0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff];
+
+var zeroLUT = [];
+
+var besttrigtab = [
+            [ 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160],
+            [ 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140],
+            [ 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160]];
+
+var J = [ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6,
+          7, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+
+var lzeroes = [
+    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0];
+
+var tabrand_chaos = [
+    0x02c57542, 0x35427717, 0x2f5a2153, 0x9244f155, 0x7bd26d07, 0x354c6052,
+    0x57329b28, 0x2993868e, 0x6cd8808c, 0x147b46e0, 0x99db66af, 0xe32b4cac,
+    0x1b671264, 0x9d433486, 0x62a4c192, 0x06089a4b, 0x9e3dce44, 0xdaabee13,
+    0x222425ea, 0xa46f331d, 0xcd589250, 0x8bb81d7f, 0xc8b736b9, 0x35948d33,
+    0xd7ac7fd0, 0x5fbe2803, 0x2cfbc105, 0x013dbc4e, 0x7a37820f, 0x39f88e9e,
+    0xedd58794, 0xc5076689, 0xfcada5a4, 0x64c2f46d, 0xb3ba3243, 0x8974b4f9,
+    0x5a05aebd, 0x20afcd00, 0x39e2b008, 0x88a18a45, 0x600bde29, 0xf3971ace,
+    0xf37b0a6b, 0x7041495b, 0x70b707ab, 0x06beffbb, 0x4206051f, 0xe13c4ee3,
+    0xc1a78327, 0x91aa067c, 0x8295f72a, 0x732917a6, 0x1d871b4d, 0x4048f136,
+    0xf1840e7e, 0x6a6048c1, 0x696cb71a, 0x7ff501c3, 0x0fc6310b, 0x57e0f83d,
+    0x8cc26e74, 0x11a525a2, 0x946934c7, 0x7cd888f0, 0x8f9d8604, 0x4f86e73b,
+    0x04520316, 0xdeeea20c, 0xf1def496, 0x67687288, 0xf540c5b2, 0x22401484,
+    0x3478658a, 0xc2385746, 0x01979c2c, 0x5dad73c8, 0x0321f58b, 0xf0fedbee,
+    0x92826ddf, 0x284bec73, 0x5b1a1975, 0x03df1e11, 0x20963e01, 0xa17cf12b,
+    0x740d776e, 0xa7a6bf3c, 0x01b5cce4, 0x1118aa76, 0xfc6fac0a, 0xce927e9b,
+    0x00bf2567, 0x806f216c, 0xbca69056, 0x795bd3e9, 0xc9dc4557, 0x8929b6c2,
+    0x789d52ec, 0x3f3fbf40, 0xb9197368, 0xa38c15b5, 0xc3b44fa8, 0xca8333b0,
+    0xb7e8d590, 0xbe807feb, 0xbf5f8360, 0xd99e2f5c, 0x372928e1, 0x7c757c4c,
+    0x0db5b154, 0xc01ede02, 0x1fc86e78, 0x1f3985be, 0xb4805c77, 0x00c880fa,
+    0x974c1b12, 0x35ab0214, 0xb2dc840d, 0x5b00ae37, 0xd313b026, 0xb260969d,
+    0x7f4c8879, 0x1734c4d3, 0x49068631, 0xb9f6a021, 0x6b863e6f, 0xcee5debf,
+    0x29f8c9fb, 0x53dd6880, 0x72b61223, 0x1f67a9fd, 0x0a0f6993, 0x13e59119,
+    0x11cca12e, 0xfe6b6766, 0x16b6effc, 0x97918fc4, 0xc2b8a563, 0x94f2f741,
+    0x0bfa8c9a, 0xd1537ae8, 0xc1da349c, 0x873c60ca, 0x95005b85, 0x9b5c080e,
+    0xbc8abbd9, 0xe1eab1d2, 0x6dac9070, 0x4ea9ebf1, 0xe0cf30d4, 0x1ef5bd7b,
+    0xd161043e, 0x5d2fa2e2, 0xff5d3cae, 0x86ed9f87, 0x2aa1daa1, 0xbd731a34,
+    0x9e8f4b22, 0xb1c2c67a, 0xc21758c9, 0xa182215d, 0xccb01948, 0x8d168df7,
+    0x04238cfe, 0x368c3dbc, 0x0aeadca5, 0xbad21c24, 0x0a71fee5, 0x9fc5d872,
+    0x54c152c6, 0xfc329483, 0x6783384a, 0xeddb3e1c, 0x65f90e30, 0x884ad098,
+    0xce81675a, 0x4b372f7d, 0x68bf9a39, 0x43445f1e, 0x40f8d8cb, 0x90d5acb6,
+    0x4cd07282, 0x349eeb06, 0x0c9d5332, 0x520b24ef, 0x80020447, 0x67976491,
+    0x2f931ca3, 0xfe9b0535, 0xfcd30220, 0x61a9e6cc, 0xa487d8d7, 0x3f7c5dd1,
+    0x7d0127c5, 0x48f51d15, 0x60dea871, 0xc9a91cb7, 0x58b53bb3, 0x9d5e0b2d,
+    0x624a78b4, 0x30dbee1b, 0x9bdf22e7, 0x1df5c299, 0x2d5643a7, 0xf4dd35ff,
+    0x03ca8fd6, 0x53b47ed8, 0x6f2c19aa, 0xfeb0c1f4, 0x49e54438, 0x2f2577e6,
+    0xbf876969, 0x72440ea9, 0xfa0bafb8, 0x74f5b3a0, 0x7dd357cd, 0x89ce1358,
+    0x6ef2cdda, 0x1e7767f3, 0xa6be9fdb, 0x4f5f88f8, 0xba994a3a, 0x08ca6b65,
+    0xe0893818, 0x9e00a16a, 0xf42bfc8f, 0x9972eedc, 0x749c8b51, 0x32c05f5e,
+    0xd706805f, 0x6bfbb7cf, 0xd9210a10, 0x31a1db97, 0x923a9559, 0x37a7a1f6,
+    0x059f8861, 0xca493e62, 0x65157e81, 0x8f6467dd, 0xab85ff9f, 0x9331aff2,
+    0x8616b9f5, 0xedbd5695, 0xee7e29b1, 0x313ac44f, 0xb903112f, 0x432ef649,
+    0xdc0a36c0, 0x61cf2bba, 0x81474925, 0xa8b6c7ad, 0xee5931de, 0xb2f8158d,
+    0x59fb7409, 0x2e3dfaed, 0x9af25a3f, 0xe1fed4d5 ];
+
+var rgb32_pixel_pad = 3;
+var rgb32_pixel_r = 2;
+var rgb32_pixel_g = 1;
+var rgb32_pixel_b = 0;
+var rgb32_pixel_size = 4;
+
+/* Helper Functions */
+
+function ceil_log_2(val)
+{
+    if (val === 1)
+        return 0;
+
+    var result = 1;
+    val -= 1;
+    while (val = val >>> 1)
+        result++;
+
+    return result;
+}
+
+function family_init(family, bpc, limit)
+{
+    var l;
+    for (l = 0; l < bpc; l++)
+    {
+        var altprefixlen, altcodewords;
+        altprefixlen = limit - bpc;
+        if (altprefixlen > bppmask[bpc - l])
+            altprefixlen = bppmask[bpc - l];
+
+        altcodewords = bppmask[bpc] + 1 - (altprefixlen << l);
+        family.nGRcodewords[l] = (altprefixlen << l);
+        family.notGRcwlen[l] = altprefixlen + ceil_log_2(altcodewords);
+        family.notGRprefixmask[l] = bppmask[32 - altprefixlen]>>>0;
+        family.notGRsuffixlen[l] = ceil_log_2(altcodewords);
+    }
+
+    /* decorelate_init */
+    var pixelbitmask = bppmask[bpc];
+    var pixelbitmaskshr = pixelbitmask >>> 1;
+    var s;
+    for (s = 0; s <= pixelbitmask; s++) {
+        if (s <= pixelbitmaskshr) {
+            family.xlatU2L[s] = s << 1;
+        } else {
+            family.xlatU2L[s] = ((pixelbitmask - s) << 1) + 1;
+        }
+    }
+
+    /* corelate_init */
+    for (s = 0; s <= pixelbitmask; s++) {
+        if (s & 0x01) {
+            family.xlatL2U[s] = pixelbitmask - (s >>> 1);
+        } else {
+            family.xlatL2U[s] = (s >>> 1);
+        }
+    }
+}
+
+function quic_image_bpc(type)
+{
+    switch (type) {
+    case Constants.QUIC_IMAGE_TYPE_GRAY:
+        return 8;
+    case Constants.QUIC_IMAGE_TYPE_RGB16:
+        return 5;
+    case Constants.QUIC_IMAGE_TYPE_RGB24:
+        return 8;
+    case Constants.QUIC_IMAGE_TYPE_RGB32:
+        return 8;
+    case Constants.QUIC_IMAGE_TYPE_RGBA:
+        return 8;
+    case Constants.QUIC_IMAGE_TYPE_INVALID:
+    default:
+        console.log("quic: bad image type\n");
+        return 0;
+    }
+}
+
+function cnt_l_zeroes(bits)
+{
+    if (bits & 0xff800000) {
+        return lzeroes[bits >>> 24];
+    } else if (bits & 0xffff8000) {
+        return 8 + lzeroes[(bits >>> 16) & 0x000000ff];
+    } else if (bits & 0xffffff80) {
+        return 16 + lzeroes[(bits >>> 8) & 0x000000ff];
+    } else {
+        return 24 + lzeroes[bits & 0x000000ff];
+    }
+}
+
+function golomb_decoding_8bpc(l, bits)
+{
+    var rc;
+    var cwlen;
+
+    if (bits < 0 || bits > family_8bpc.notGRprefixmask[l])
+    {
+        var zeroprefix = cnt_l_zeroes(bits);
+        cwlen = zeroprefix + 1 + l;
+        rc = (zeroprefix << l) | (bits >> (32-cwlen)) & bppmask[l];
+    }
+    else
+    {
+        cwlen = family_8bpc.notGRcwlen[l];
+        rc = family_8bpc.nGRcodewords[l] + ((bits >> (32-cwlen)) & bppmask[family_8bpc.notGRsuffixlen[l]]);
+    }
+    return {'codewordlen':cwlen, 'rc':rc};
+}
+
+function golomb_code_len_8bpc(n, l)
+{
+    if (n < family_8bpc.nGRcodewords[l]) {
+        return (n >>> l) + 1 + l;
+    } else {
+        return family_8bpc.notGRcwlen[l];
+    }
+}
+
+function QuicModel(bpc)
+{
+    var bstart;
+    var bend = 0;
+
+    this.levels = 0x1 << bpc;
+    this.n_buckets_ptrs = 0;
+
+    switch (evol) {
+        case 1:
+            this.repfirst = 3;
+            this.firstsize = 1;
+            this.repnext = 2;
+            this.mulsize = 2;
+            break;
+        case 3:
+            this.repfirst = 1;
+            this.firstsize = 1;
+            this.repnext = 1;
+            this.mulsize = 2;
+            break;
+        case 5:
+            this.repfirst = 1;
+            this.firstsize = 1;
+            this.repnext = 1;
+            this.mulsize = 4;
+            break;
+        case 0:
+        case 2:
+        case 4:
+            console.log("quic: findmodelparams(): evol value obsolete!!!\n");
+            break;
+        default:
+            console.log("quic: findmodelparams(): evol out of range!!!\n");
+    }
+
+    this.n_buckets = 0;
+    var repcntr = this.repfirst + 1;
+    var bsize = this.firstsize;
+
+    do {
+        if (this.n_buckets) {
+            bstart = bend + 1;
+        } else {
+            bstart = 0;
+        }
+
+        if (!--repcntr) {
+            repcntr = this.repnext;
+            bsize *= this.mulsize;
+        }
+
+        bend = bstart + bsize - 1;
+        if (bend + bsize >= this.levels) {
+            bend = this.levels - 1;
+        }
+
+        if (!this.n_buckets_ptrs) {
+            this.n_buckets_ptrs = this.levels;
+        }
+
+        (this.n_buckets)++;
+    } while (bend < this.levels - 1);
+}
+
+QuicModel.prototype = {
+    n_buckets : 0,
+    n_buckets_ptrs : 0,
+    repfirst : 0,
+    firstsize : 0,
+    repnext : 0,
+    mulsize : 0,
+    levels :0
+}
+
+function QuicBucket()
+{
+    this.counters = [0,0,0,0,0,0,0,0];
+}
+
+QuicBucket.prototype = {
+    bestcode: 0,
+
+    reste : function (bpp)
+    {
+        this.bestcode = bpp;
+        this.counters = [0,0,0,0,0,0,0,0];
+    },
+
+    update_model_8bpc : function (state, curval, bpp)
+    {
+        var i;
+
+        var bestcode = bpp - 1;
+        var bestcodelen = (this.counters[bestcode] += golomb_code_len_8bpc(curval, bestcode));
+
+        for (i = bpp - 2; i >= 0; i--) {
+            var ithcodelen = (this.counters[i] += golomb_code_len_8bpc(curval, i));
+
+            if (ithcodelen < bestcodelen) {
+                bestcode = i;
+                bestcodelen = ithcodelen;
+            }
+        }
+
+        this.bestcode = bestcode;
+
+        if (bestcodelen > state.wm_trigger) {
+            for (i = 0; i < bpp; i++) {
+                this.counters[i] = this.counters[i] >>> 1;
+            }
+        }
+    }
+}
+
+function QuicFamilyStat()
+{
+    this.buckets_ptrs = [];
+    this.buckets_buf = [];
+}
+
+QuicFamilyStat.prototype = {
+
+    fill_model_structures : function(model)
+    {
+        var bstart;
+        var bend = 0;
+        var bnumber = 0;
+
+        var repcntr = model.repfirst + 1;
+        var bsize = model.firstsize;
+
+        do {
+            if (bnumber) {
+                bstart = bend + 1;
+            } else {
+                bstart = 0;
+            }
+
+            if (!--repcntr) {
+                repcntr = model.repnext;
+                bsize *= model.mulsize;
+            }
+
+            bend = bstart + bsize - 1;
+            if (bend + bsize >= model.levels) {
+                bend = model.levels - 1;
+            }
+
+            this.buckets_buf[bnumber] = new QuicBucket;
+
+            var i;
+            for (i = bstart; i <= bend; i++) {
+                this.buckets_ptrs[i] = this.buckets_buf[bnumber];
+            }
+
+            bnumber++;
+        } while (bend < model.levels - 1);
+        return true;
+    }
+}
+
+function QuicChannel(model_8bpc, model_5bpc)
+{
+    this.state = new CommonState;
+    this.family_stat_8bpc = new QuicFamilyStat;
+    this.family_stat_5bpc = new QuicFamilyStat;
+    this.correlate_row = { zero: 0 , row:[] };
+    this.model_8bpc = model_8bpc;
+    this.model_5bpc = model_5bpc;
+    this.buckets_ptrs = [];
+
+    if (!this.family_stat_8bpc.fill_model_structures(this.model_8bpc))
+        return undefined;
+
+    if (!this.family_stat_5bpc.fill_model_structures(this.model_5bpc))
+        return undefined;
+}
+
+QuicChannel.prototype = {
+
+    reste : function (bpc)
+    {
+        var j;
+        this.correlate_row = { zero: 0 , row: []};
+
+        if (bpc == 8) {
+            for (j = 0; j < this.model_8bpc.n_buckets; j++)
+                this.family_stat_8bpc.buckets_buf[j].reste(7);
+            this.buckets_ptrs = this.family_stat_8bpc.buckets_ptrs;
+        } else if (bpc == 5) {
+            for (j = 0; j < this.model_5bpc.n_buckets; j++)
+                this.family_stat_8bpc.buckets_buf[j].reste(4);
+            this.buckets_ptrs = this.family_stat_5bpc.buckets_ptrs;
+        } else {
+            console.log("quic: %s: bad bpc %d\n", __FUNCTION__, bpc);
+            return false;
+        }
+
+        this.state.reste();
+        return true;
+    }
+}
+
+function CommonState()
+{
+}
+
+CommonState.prototype = {
+    waitcnt: 0,
+    tabrand_seed: 0xff,
+    wm_trigger: 0,
+    wmidx: 0,
+    wmileft: wminext,
+    melcstate: 0,
+    melclen: 0,
+    melcorder: 0,
+
+    set_wm_trigger : function()
+    {
+        var wm = this.wmidx;
+        if (wm > 10) {
+            wm = 10;
+        }
+
+        this.wm_trigger = besttrigtab[Math.floor(evol / 2)][wm];
+    },
+
+    reste : function()
+    {
+        this.waitcnt = 0;
+        this.tabrand_seed = 0x0ff;
+        this.wmidx = 0;
+        this.wmileft = wminext;
+
+        this.set_wm_trigger();
+
+        this.melcstate = 0;
+        this.melclen = J[0];
+        this.melcorder = 1 << this.melclen;
+    },
+
+    tabrand : function()
+    {
+        this.tabrand_seed++;
+        return tabrand_chaos[this.tabrand_seed & 0x0ff];
+    }
+}
+
+
+function QuicEncoder()
+{
+    this.rgb_state = new CommonState;
+    this.model_8bpc = new QuicModel(8);
+    this.model_5bpc = new QuicModel(5);
+    this.channels = [];
+
+    var i;
+    for (i = 0; i < 4; i++) {
+        this.channels[i] = new QuicChannel(this.model_8bpc, this.model_5bpc);
+        if (!this.channels[i])
+        {
+            console.log("quic: failed to create channel");
+            return undefined;
+        }
+    }
+}
+
+QuicEncoder.prototype = {
+                    type: 0,
+                    width: 0,
+                    height: 0,
+                    io_idx: 0,
+                    io_available_bits: 0,
+                    io_word: 0,
+                    io_next_word: 0,
+                    io_now: 0,
+                    io_end: 0,
+                    rows_completed: 0,
+              };
+
+QuicEncoder.prototype.reste = function(io_ptr)
+{
+    this.rgb_state.reste();
+
+    this.io_now = io_ptr;
+    this.io_end = this.io_now.length;
+    this.io_idx = 0;
+    this.rows_completed = 0;
+    return true;
+}
+
+QuicEncoder.prototype.read_io_word = function()
+{
+    if (this.io_idx >= this.io_end)
+        throw("quic: out of data");
+    this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24;
+}
+
+QuicEncoder.prototype.decode_eatbits = function (len)
+{
+    this.io_word = this.io_word << len;
+
+    var delta = (this.io_available_bits - len);
+    if (delta >= 0)
+    {
+        this.io_available_bits = delta;
+        this.io_word |= this.io_next_word >>> this.io_available_bits;
+    }
+    else
+    {
+        delta = -1 * delta;
+        this.io_word |= this.io_next_word << delta;
+        this.read_io_word();
+        this.io_available_bits = 32 - delta;
+        this.io_word |= this.io_next_word >>> this.io_available_bits;
+    }
+}
+
+QuicEncoder.prototype.decode_eat32bits = function()
+{
+    this.decode_eatbits(16);
+    this.decode_eatbits(16);
+}
+
+QuicEncoder.prototype.reste_channels = function(bpc)
+{
+    var i;
+
+    for (i = 0; i < 4; i++)
+        if (!this.channels[i].reste(bpc))
+            return false;
+    return true;
+}
+
+QuicEncoder.prototype.quic_decode_begin = function(io_ptr)
+{
+    if (!this.reste(io_ptr)) {
+        return false;
+    }
+
+    this.io_idx = 0;
+    this.io_next_word = this.io_now[this.io_idx++] | this.io_now[this.io_idx++]<<8 | this.io_now[this.io_idx++]<<16 | this.io_now[this.io_idx++]<<24;
+    this.io_word = this.io_next_word;
+    this.io_available_bits = 0;
+
+    var magic = this.io_word;
+    this.decode_eat32bits();
+    if (magic != 0x43495551) /*QUIC*/ {
+        console.log("quic: bad magic "+magic.toString(16));
+        return false;
+    }
+
+    var version = this.io_word;
+    this.decode_eat32bits();
+    if (version != ((0 << 16) | (0 & 0xffff))) {
+        console.log("quic: bad version "+version.toString(16));
+        return false;
+    }
+
+    this.type = this.io_word;
+    this.decode_eat32bits();
+
+    this.width = this.io_word;
+    this.decode_eat32bits();
+
+    this.height = this.io_word;
+    this.decode_eat32bits();
+
+    var bpc = quic_image_bpc(this.type);
+
+    if (!this.reste_channels(bpc))
+        return false;
+
+    return true;
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row0_seg = function (i, cur_row, end,
+                                       waitmask, bpc, bpc_mask)
+{
+    var stopidx;
+    var n_channels = 3;
+    var c;
+    var a;
+
+    if (!i) {
+        cur_row[rgb32_pixel_pad] = 0;
+        c = 0;
+        do
+        {
+            a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word);
+            this.channels[c].correlate_row.row[0] = a.rc;
+            cur_row[2-c] = (family_8bpc.xlatL2U[a.rc]&0xFF);
+            this.decode_eatbits(a.codewordlen);
+        } while (++c < n_channels);
+
+        if (this.rgb_state.waitcnt) {
+            --this.rgb_state.waitcnt;
+        } else {
+            this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask);
+            c = 0;
+            do
+            {
+                this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc);
+            } while (++c < n_channels);
+        }
+        stopidx = ++i + this.rgb_state.waitcnt;
+    } else {
+        stopidx = i + this.rgb_state.waitcnt;
+    }
+
+    while (stopidx < end) {
+        for (; i <= stopidx; i++) {
+            cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0;
+            c = 0;
+            do
+            {
+                a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word);
+                this.channels[c].correlate_row.row[i] = a.rc;
+                cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask;
+                this.decode_eatbits(a.codewordlen);
+            } while (++c < n_channels);
+        }
+        c = 0;
+        do
+        {
+            this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc);
+        } while (++c < n_channels);
+        stopidx = i + (this.rgb_state.tabrand() & waitmask);
+    }
+
+    for (; i < end; i++) {
+        cur_row[(i* rgb32_pixel_size)+rgb32_pixel_pad] = 0;
+        c = 0;
+        do
+        {
+            a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i - 1]].bestcode, this.io_word);
+            this.channels[c].correlate_row.row[i] = a.rc;
+            cur_row[(i* rgb32_pixel_size)+(2-c)] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1) * rgb32_pixel_size) + (2-c)]) & bpc_mask;
+            this.decode_eatbits(a.codewordlen);
+        } while (++c < n_channels);
+    }
+    this.rgb_state.waitcnt = stopidx - end;
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row0 = function (cur_row)
+{
+    var bpc = 8;
+    var bpc_mask = 0xff;
+    var pos = 0;
+    var width = this.width;
+
+    while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) {
+        if (this.rgb_state.wmileft) {
+            this.quic_rgb32_uncompress_row0_seg(pos, cur_row,
+                                       pos + this.rgb_state.wmileft,
+                                       bppmask[this.rgb_state.wmidx],
+                                       bpc, bpc_mask);
+            pos += this.rgb_state.wmileft;
+            width -= this.rgb_state.wmileft;
+        }
+
+        this.rgb_state.wmidx++;
+        this.rgb_state.set_wm_trigger();
+        this.rgb_state.wmileft = wminext;
+    }
+
+    if (width) {
+        this.quic_rgb32_uncompress_row0_seg(pos, cur_row, pos + width,
+                                   bppmask[this.rgb_state.wmidx], bpc, bpc_mask);
+        if (wmimax > this.rgb_state.wmidx) {
+            this.rgb_state.wmileft -= width;
+        }
+    }
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row_seg = function( prev_row, cur_row, i, end, bpc, bpc_mask)
+{
+    var n_channels = 3;
+    var waitmask = bppmask[this.rgb_state.wmidx];
+
+    var a;
+    var run_index = 0;
+    var stopidx = 0;
+    var run_end = 0;
+    var c;
+
+    if (!i)
+    {
+        cur_row[rgb32_pixel_pad] = 0;
+
+        c = 0;
+        do {
+            a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].bestcode, this.io_word);
+            this.channels[c].correlate_row.row[0] = a.rc;
+            cur_row[2-c] = (family_8bpc.xlatL2U[this.channels[c].correlate_row.row[0]] + prev_row[2-c]) & bpc_mask;
+            this.decode_eatbits(a.codewordlen);
+        } while (++c < n_channels);
+
+        if (this.rgb_state.waitcnt) {
+            --this.rgb_state.waitcnt;
+        } else {
+            this.rgb_state.waitcnt = (this.rgb_state.tabrand() & waitmask);
+            c = 0;
+            do {
+                this.channels[c].buckets_ptrs[this.channels[c].correlate_row.zero].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[0], bpc);
+            } while (++c < n_channels);
+        }
+        stopidx = ++i + this.rgb_state.waitcnt;
+    } else {
+        stopidx = i + this.rgb_state.waitcnt;
+    }
+    for (;;) {
+        var rc = 0;
+        while (stopidx < end && !rc) {
+            for (; i <= stopidx && !rc; i++) {
+                var pixel = i * rgb32_pixel_size;
+                var pixelm1 = (i-1) * rgb32_pixel_size;
+                var pixelm2 = (i-2) * rgb32_pixel_size;
+
+                if ( prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1 + rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b])
+                {
+                    if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b]))
+                    {
+                        /* do run */
+                        this.rgb_state.waitcnt = stopidx - i;
+                        run_index = i;
+                        run_end = i + this.decode_run(this.rgb_state);
+
+                        for (; i < run_end; i++) {
+                            var pixel = i * rgb32_pixel_size;
+                            var pixelm1 = (i-1) * rgb32_pixel_size;
+                            cur_row[pixel+rgb32_pixel_pad] = 0;
+                            cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r];
+                            cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g];
+                            cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b];
+                        }
+
+                        if (i == end) {
+                            return;
+                        }
+                        else
+                        {
+                            stopidx = i + this.rgb_state.waitcnt;
+                            rc = 1;
+                            break;
+                        }
+                    }
+                }
+
+                c = 0;
+                cur_row[pixel+rgb32_pixel_pad] = 0;
+                do {
+                    var cc = this.channels[c];
+                    var cr = cc.correlate_row;
+
+                    a = golomb_decoding_8bpc(cc.buckets_ptrs[cr.row[i-1]].bestcode, this.io_word);
+                    cr.row[i] = a.rc;
+                cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask;
+                    this.decode_eatbits(a.codewordlen);
+                } while (++c < n_channels);
+            }
+            if (rc)
+                break;
+
+            c = 0;
+            do {
+                this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[stopidx - 1]].update_model_8bpc(this.rgb_state, this.channels[c].correlate_row.row[stopidx], bpc);
+            } while (++c < n_channels);
+
+            stopidx = i + (this.rgb_state.tabrand() & waitmask);
+        }
+
+        for (; i < end && !rc; i++) {
+            var pixel = i * rgb32_pixel_size;
+            var pixelm1 = (i-1) * rgb32_pixel_size;
+            var pixelm2 = (i-2) * rgb32_pixel_size;
+
+            if (prev_row[pixelm1+rgb32_pixel_r] == prev_row[pixel+rgb32_pixel_r] && prev_row[pixelm1+rgb32_pixel_g] == prev_row[pixel+rgb32_pixel_g] && prev_row[pixelm1+rgb32_pixel_b] == prev_row[pixel+rgb32_pixel_b])
+            {
+                if (run_index != i && i > 2 && (cur_row[pixelm1+rgb32_pixel_r] == cur_row[pixelm2+rgb32_pixel_r] && cur_row[pixelm1+rgb32_pixel_g] == cur_row[pixelm2+rgb32_pixel_g] && cur_row[pixelm1+rgb32_pixel_b] == cur_row[pixelm2+rgb32_pixel_b]))
+                {
+                    /* do run */
+                    this.rgb_state.waitcnt = stopidx - i;
+                    run_index = i;
+                    run_end = i + this.decode_run(this.rgb_state);
+
+                    for (; i < run_end; i++) {
+                        var pixel = i * rgb32_pixel_size;
+                        var pixelm1 = (i-1) * rgb32_pixel_size;
+                        cur_row[pixel+rgb32_pixel_pad] = 0;
+                        cur_row[pixel+rgb32_pixel_r] = cur_row[pixelm1+rgb32_pixel_r];
+                        cur_row[pixel+rgb32_pixel_g] = cur_row[pixelm1+rgb32_pixel_g];
+                        cur_row[pixel+rgb32_pixel_b] = cur_row[pixelm1+rgb32_pixel_b];
+                    }
+
+                    if (i == end) {
+                        return;
+                    }
+                    else
+                    {
+                        stopidx = i + this.rgb_state.waitcnt;
+                        rc = 1;
+                        break;
+                    }
+                }
+            }
+
+            cur_row[pixel+rgb32_pixel_pad] = 0;
+            c = 0;
+            do
+            {
+                a = golomb_decoding_8bpc(this.channels[c].buckets_ptrs[this.channels[c].correlate_row.row[i-1]].bestcode, this.io_word);
+                this.channels[c].correlate_row.row[i] = a.rc;
+                cur_row[pixel+(2-c)] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+(2-c)] + prev_row[pixel+(2-c)]) >> 1)) & bpc_mask;
+                this.decode_eatbits(a.codewordlen);
+            } while (++c < n_channels);
+        }
+
+          if (!rc)
+          {
+            this.rgb_state.waitcnt = stopidx - end;
+            return;
+          }
+        }
+}
+
+QuicEncoder.prototype.decode_run = function(state)
+{
+    var runlen = 0;
+
+    do {
+        var hits;
+        var x = (~(this.io_word >>> 24)>>>0)&0xff;
+        var temp = zeroLUT[x];
+
+        for (hits = 1; hits <= temp; hits++) {
+            runlen += state.melcorder;
+
+            if (state.melcstate < 32) {
+                state.melclen = J[++state.melcstate];
+                state.melcorder = (1 << state.melclen);
+            }
+        }
+        if (temp != 8) {
+            this.decode_eatbits(temp + 1);
+
+            break;
+        }
+        this.decode_eatbits(8);
+    } while (true);
+
+    if (state.melclen) {
+        runlen += this.io_word >>> (32 - state.melclen);
+        this.decode_eatbits(state.melclen);
+    }
+
+    if (state.melcstate) {
+        state.melclen = J[--state.melcstate];
+        state.melcorder = (1 << state.melclen);
+    }
+
+    return runlen;
+}
+
+QuicEncoder.prototype.quic_rgb32_uncompress_row = function (prev_row, cur_row)
+{
+    var bpc = 8;
+    var bpc_mask = 0xff;
+    var pos = 0;
+    var width = this.width;
+
+    while ((wmimax > this.rgb_state.wmidx) && (this.rgb_state.wmileft <= width)) {
+        if (this.rgb_state.wmileft) {
+            this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos,
+                                      pos + this.rgb_state.wmileft, bpc, bpc_mask);
+            pos += this.rgb_state.wmileft;
+            width -= this.rgb_state.wmileft;
+        }
+
+        this.rgb_state.wmidx++;
+        this.rgb_state.set_wm_trigger();
+        this.rgb_state.wmileft = wminext;
+    }
+
+    if (width) {
+        this.quic_rgb32_uncompress_row_seg(prev_row, cur_row, pos,
+                                  pos + width, bpc, bpc_mask);
+        if (wmimax > this.rgb_state.wmidx) {
+            this.rgb_state.wmileft -= width;
+        }
+    }
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row0_seg = function (channel, i,
+                                       correlate_row, cur_row, end, waitmask,
+                                       bpc, bpc_mask)
+{
+    var stopidx;
+    var a;
+
+    if (i == 0) {
+        a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word);
+        correlate_row.row[0] = a.rc;
+        cur_row[rgb32_pixel_pad] = family_8bpc.xlatL2U[a.rc];
+        this.decode_eatbits(a.codewordlen);
+
+        if (channel.state.waitcnt) {
+            --channel.state.waitcnt;
+        } else {
+            channel.state.waitcnt = (channel.state.tabrand() & waitmask);
+            channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc);
+        }
+        stopidx = ++i + channel.state.waitcnt;
+    } else {
+        stopidx = i + channel.state.waitcnt;
+    }
+
+    while (stopidx < end) {
+        var pbucket;
+
+        for (; i <= stopidx; i++) {
+            pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]];
+
+            a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word);
+            correlate_row.row[i] = a.rc;
+            cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask;
+            this.decode_eatbits(a.codewordlen);
+        }
+
+        pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc);
+
+        stopidx = i + (channel.state.tabrand() & waitmask);
+    }
+
+    for (; i < end; i++) {
+        a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word);
+
+        correlate_row.row[i] = a.rc;
+        cur_row[(i*rgb32_pixel_size)+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + cur_row[((i-1)*rgb32_pixel_size)+rgb32_pixel_pad]) & bpc_mask;
+        this.decode_eatbits(a.codewordlen);
+    }
+    channel.state.waitcnt = stopidx - end;
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row0 = function(channel, cur_row)
+{
+    var bpc = 8;
+    var bpc_mask = 0xff;
+    var correlate_row = channel.correlate_row;
+    var pos = 0;
+    var width = this.width;
+
+    while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) {
+        if (channel.state.wmileft) {
+            this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row,
+                                       pos + channel.state.wmileft, bppmask[channel.state.wmidx],
+                                       bpc, bpc_mask);
+            pos += channel.state.wmileft;
+            width -= channel.state.wmileft;
+        }
+
+        channel.state.wmidx++;
+        channel.state.set_wm_trigger();
+        channel.state.wmileft = wminext;
+    }
+
+    if (width) {
+        this.quic_four_uncompress_row0_seg(channel, pos, correlate_row, cur_row, pos + width,
+                                   bppmask[channel.state.wmidx], bpc, bpc_mask);
+        if (wmimax > channel.state.wmidx) {
+            channel.state.wmileft -= width;
+        }
+    }
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row_seg = function (channel,
+                                      correlate_row, prev_row, cur_row, i,
+                                      end, bpc, bpc_mask)
+{
+    var waitmask = bppmask[channel.state.wmidx];
+    var stopidx;
+
+    var run_index = 0;
+    var run_end;
+
+    var a;
+
+    if (i == 0) {
+        a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.zero].bestcode, this.io_word);
+
+        correlate_row.row[0] = a.rc
+        cur_row[rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + prev_row[rgb32_pixel_pad]) & bpc_mask;
+        this.decode_eatbits(a.codewordlen);
+
+        if (channel.state.waitcnt) {
+            --channel.state.waitcnt;
+        } else {
+            channel.state.waitcnt = (channel.state.tabrand() & waitmask);
+            channel.buckets_ptrs[correlate_row.zero].update_model_8bpc(channel.state, correlate_row.row[0], bpc);
+        }
+        stopidx = ++i + channel.state.waitcnt;
+    } else {
+        stopidx = i + channel.state.waitcnt;
+    }
+    for (;;) {
+        var rc = 0;
+        while (stopidx < end && !rc) {
+            var pbucket;
+            for (; i <= stopidx && !rc; i++) {
+                var pixel = i * rgb32_pixel_size;
+                var pixelm1 = (i-1) * rgb32_pixel_size;
+                var pixelm2 = (i-2) * rgb32_pixel_size;
+
+                if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad])
+                {
+                    if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad])
+                    {
+                        /* do run */
+                        channel.state.waitcnt = stopidx - i;
+                        run_index = i;
+
+                        run_end = i + this.decode_run(channel.state);
+
+                        for (; i < run_end; i++) {
+                            var pixel = i * rgb32_pixel_size;
+                            var pixelm1 = (i-1) * rgb32_pixel_size;
+                            cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad];
+                        }
+
+                        if (i == end) {
+                            return;
+                        }
+                        else
+                        {
+                            stopidx = i + channel.state.waitcnt;
+                            rc = 1;
+                            break;
+                        }
+                    }
+                }
+
+                pbucket = channel.buckets_ptrs[correlate_row.row[i - 1]];
+                a = golomb_decoding_8bpc(pbucket.bestcode, this.io_word);
+                correlate_row.row[i] = a.rc
+                cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask;
+                this.decode_eatbits(a.codewordlen);
+            }
+            if (rc)
+                break;
+
+            pbucket.update_model_8bpc(channel.state, correlate_row.row[stopidx], bpc);
+
+            stopidx = i + (channel.state.tabrand() & waitmask);
+        }
+
+        for (; i < end && !rc; i++) {
+            var pixel = i * rgb32_pixel_size;
+            var pixelm1 = (i-1) * rgb32_pixel_size;
+            var pixelm2 = (i-2) * rgb32_pixel_size;
+            if (prev_row[pixelm1+rgb32_pixel_pad] == prev_row[pixel+rgb32_pixel_pad])
+            {
+                if (run_index != i && i > 2 && cur_row[pixelm1+rgb32_pixel_pad] == cur_row[pixelm2+rgb32_pixel_pad])
+                {
+                    /* do run */
+                    channel.state.waitcnt = stopidx - i;
+                    run_index = i;
+
+                    run_end = i + this.decode_run(channel.state);
+
+                    for (; i < run_end; i++) {
+                        var pixel = i * rgb32_pixel_size;
+                        var pixelm1 = (i-1) * rgb32_pixel_size;
+                        cur_row[pixel+rgb32_pixel_pad] = cur_row[pixelm1+rgb32_pixel_pad];
+                    }
+
+                    if (i == end) {
+                        return;
+                    }
+                    else
+                    {
+                        stopidx = i + channel.state.waitcnt;
+                        rc = 1;
+                        break;
+                    }
+                }
+            }
+
+            a = golomb_decoding_8bpc(channel.buckets_ptrs[correlate_row.row[i-1]].bestcode, this.io_word);
+            correlate_row.row[i] = a.rc;
+            cur_row[pixel+rgb32_pixel_pad] = (family_8bpc.xlatL2U[a.rc] + ((cur_row[pixelm1+rgb32_pixel_pad] + prev_row[pixel+rgb32_pixel_pad]) >> 1)) & bpc_mask;
+            this.decode_eatbits(a.codewordlen);
+        }
+
+        if (!rc)
+        {
+            channel.state.waitcnt = stopidx - end;
+            return;
+        }
+    }
+}
+
+QuicEncoder.prototype.quic_four_uncompress_row = function(channel, prev_row,
+                                                        cur_row)
+{
+    var bpc = 8;
+    var bpc_mask = 0xff;
+    var correlate_row = channel.correlate_row;
+    var pos = 0;
+    var width = this.width;
+
+    while ((wmimax > channel.state.wmidx) && (channel.state.wmileft <= width)) {
+        if (channel.state.wmileft) {
+            this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos,
+                                      pos + channel.state.wmileft, bpc, bpc_mask);
+            pos += channel.state.wmileft;
+            width -= channel.state.wmileft;
+        }
+
+        channel.state.wmidx++;
+        channel.state.set_wm_trigger();
+        channel.state.wmileft = wminext;
+    }
+
+    if (width) {
+        this.quic_four_uncompress_row_seg(channel, correlate_row, prev_row, cur_row, pos,
+                                  pos + width, bpc, bpc_mask);
+        if (wmimax > channel.state.wmidx) {
+            channel.state.wmileft -= width;
+        }
+    }
+}
+
+/* We need to be generating rgb32 or rgba */
+QuicEncoder.prototype.quic_decode = function(buf, stride)
+{
+    var row;
+
+    switch (this.type)
+    {
+        case Constants.QUIC_IMAGE_TYPE_RGB32:
+        case Constants.QUIC_IMAGE_TYPE_RGB24:
+            this.channels[0].correlate_row.zero = 0;
+            this.channels[1].correlate_row.zero = 0;
+            this.channels[2].correlate_row.zero = 0;
+            this.quic_rgb32_uncompress_row0(buf);
+
+            this.rows_completed++;
+            for (row = 1; row < this.height; row++)
+            {
+                var prev = buf;
+                buf = prev.subarray(stride);
+                this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0];
+                this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0];
+                this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0];
+                this.quic_rgb32_uncompress_row(prev, buf);
+                this.rows_completed++;
+            };
+            break;
+        case Constants.QUIC_IMAGE_TYPE_RGB16:
+            console.log("quic: unsupported output format\n");
+            return false;
+            break;
+        case Constants.QUIC_IMAGE_TYPE_RGBA:
+            this.channels[0].correlate_row.zero = 0;
+            this.channels[1].correlate_row.zero = 0;
+            this.channels[2].correlate_row.zero = 0;
+            this.quic_rgb32_uncompress_row0(buf);
+
+            this.channels[3].correlate_row.zero = 0;
+            this.quic_four_uncompress_row0(this.channels[3], buf);
+
+            this.rows_completed++;
+            for (row = 1; row < this.height; row++) {
+                var prev = buf;
+                buf = prev.subarray(stride);
+
+                this.channels[0].correlate_row.zero = this.channels[0].correlate_row.row[0];
+                this.channels[1].correlate_row.zero = this.channels[1].correlate_row.row[0];
+                this.channels[2].correlate_row.zero = this.channels[2].correlate_row.row[0];
+                this.quic_rgb32_uncompress_row(prev, buf);
+
+                this.channels[3].correlate_row.zero = this.channels[3].correlate_row.row[0];
+                this.quic_four_uncompress_row(encoder.channels[3], prev, buf);
+                this.rows_completed++;
+            }
+            break;
+
+        case Constants.QUIC_IMAGE_TYPE_GRAY:
+            console.log("quic: unsupported output format\n");
+            return false;
+            break;
+
+        case Constants.QUIC_IMAGE_TYPE_INVALID:
+        default:
+            console.log("quic: bad image type\n");
+            return false;
+    }
+    return true;
+}
+
+QuicEncoder.prototype.simple_quic_decode = function(buf)
+{
+    var stride = 4; /* FIXME - proper stride calc please */
+    if (!this.quic_decode_begin(buf))
+        return undefined;
+    if (this.type != Constants.QUIC_IMAGE_TYPE_RGB32 && this.type != Constants.QUIC_IMAGE_TYPE_RGB24
+        && this.type != Constants.QUIC_IMAGE_TYPE_RGBA)
+        return undefined;
+    var out = new Uint8Array(this.width*this.height*4);
+    out[0] = 69;
+    if (this.quic_decode( out, (this.width * stride)))
+        return out;
+    return undefined;
+}
+
+function SpiceQuic()
+{
+}
+
+SpiceQuic.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        if (!encoder)
+            throw("quic: no quic encoder");
+        this.data_size = dv.getUint32(at, true);
+        at += 4;
+        var buf = new Uint8Array(mb.slice(at));
+        this.outptr = encoder.simple_quic_decode(buf);
+        if (this.outptr)
+        {
+            this.type = encoder.type;
+            this.width = encoder.width;
+            this.height = encoder.height;
+        }
+        at += buf.length;
+        return at;
+    },
+}
+
+function convert_spice_quic_to_web(context, spice_quic)
+{
+    var ret = context.createImageData(spice_quic.width, spice_quic.height);
+    var i;
+    for (i = 0; i < (ret.width * ret.height * 4); i+=4)
+    {
+        ret.data[i + 0] = spice_quic.outptr[i + 2];
+        ret.data[i + 1] = spice_quic.outptr[i + 1];
+        ret.data[i + 2] = spice_quic.outptr[i + 0];
+        if (spice_quic.type !== Constants.QUIC_IMAGE_TYPE_RGBA)
+            ret.data[i + 3] = 255;
+        else
+            ret.data[i + 3] = 255 - spice_quic.outptr[i + 3];
+    }
+   return ret;
+}
+
+/* Module initialization */
+if (need_init)
+{
+    need_init = false;
+
+    family_init(family_8bpc, 8, DEFmaxclen);
+    family_init(family_5bpc, 5, DEFmaxclen);
+    /* init_zeroLUT */
+    var i, j, k, l;
+
+    j = k = 1;
+    l = 8;
+    for (i = 0; i < 256; ++i) {
+        zeroLUT[i] = l;
+        --k;
+        if (k == 0) {
+            k = j;
+            --l;
+            j *= 2;
+        }
+    }
+
+    encoder = new QuicEncoder;
+
+    if (!encoder)
+        throw("quic: failed to create encoder");
+}
+
+export {
+  Constants,
+  SpiceQuic,
+  convert_spice_quic_to_web,
+};
diff -pruN 0.1.7-5/src/resize.js 0.2.2-0ubuntu3/src/resize.js
--- 0.1.7-5/src/resize.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/resize.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,90 @@
+"use strict";
+/*
+   Copyright (C) 2014 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  resize.js
+**      This bit of Javascript is a set of logic to help with window
+**  resizing, using the agent channel to request screen resizes.
+**
+**  It's a bit tricky, as we want to wait for resizing to settle down
+**  before sending a size.  Further, while horizontal resizing to use the whole
+**  browser width is fairly easy to arrange with css, resizing an element to use
+**  the whole vertical space (or to force a middle div to consume the bulk of the browser
+**  window size) is tricky, and the consensus seems to be that Javascript is
+**  the only right way to do it.
+**--------------------------------------------------------------------------*/
+function resize_helper(sc)
+{
+    var w = document.getElementById(sc.screen_id).clientWidth;
+    var m = document.getElementById(sc.message_id);
+
+    /* Resize vertically; basically we leave a 20 pixel margin
+         at the bottom, and use the position of the message window
+         to figure out how to resize */
+
+    var h = window.innerHeight - 20;
+
+    /* Screen height based on debug console visibility  */
+    if (m != null)
+    {
+        if (window.getComputedStyle(m).getPropertyValue("display") == 'none')
+        {
+            /* Get console height from spice.css .spice-message */
+            var mh = parseInt(window.getComputedStyle(m).getPropertyValue("height"), 10);
+            h = h - mh;
+        }
+        else
+        {
+            /* Show both div elements - spice-area and message-div */
+            h = h - m.offsetHeight - m.clientHeight;
+        }
+    }
+
+
+    /* Xorg requires height be a multiple of 8; round down */
+    if (h % 8 > 0)
+        h -= (h % 8);
+
+    /* Xorg requires width be a multiple of 8; round down */
+    if (w % 8 > 0)
+        w -= (w % 8);
+
+
+    sc.resize_window(0, w, h, 32, 0, 0);
+    sc.spice_resize_timer = undefined;
+}
+
+function handle_resize(e)
+{
+    var sc = window.spice_connection;
+
+    if (sc && sc.spice_resize_timer)
+    {
+        window.clearTimeout(sc.spice_resize_timer);
+        sc.spice_resize_timer = undefined;
+    }
+
+    sc.spice_resize_timer = window.setTimeout(resize_helper, 200, sc);
+}
+
+export {
+  resize_helper,
+  handle_resize,
+};
diff -pruN 0.1.7-5/src/simulatecursor.js 0.2.2-0ubuntu3/src/simulatecursor.js
--- 0.1.7-5/src/simulatecursor.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/simulatecursor.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,208 @@
+"use strict";
+/*
+   Copyright (C) 2013 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  SpiceSimulateCursor
+**      Internet Explorer 10 does not support data uri's in cursor assignment.
+**  This file provides a number of gimmicks to compensate.  First, if there
+**  is a preloaded cursor available, we will use that.  Failing that, we will
+**  simulate a cursor using an image that is moved around the screen.
+**--------------------------------------------------------------------------*/
+
+import { SpiceDataView } from './spicedataview.js';
+import { hex_sha1 } from './thirdparty/sha1.js';
+
+var SpiceSimulateCursor = {
+
+cursors : new Array(),
+unknown_cursors : new Array(),
+warned: false,
+
+add_cursor: function(sha1, value)
+{
+    SpiceSimulateCursor.cursors[sha1] = value;
+},
+
+unknown_cursor: function(sha1, curdata)
+{
+    if (! SpiceSimulateCursor.warned)
+    {
+        SpiceSimulateCursor.warned = true;
+        alert("Internet Explorer does not support dynamic cursors.  " +
+              "This page will now simulate cursors with images, " +
+              "which will be imperfect.  We recommend using Chrome or Firefox instead.  " +
+              "\n\nIf you need to use Internet Explorer, you can create a static cursor " +
+              "file for each cursor your application uses.  " +
+              "View the console log for more information on creating static cursors for your environment.");
+    }
+
+    if (! SpiceSimulateCursor.unknown_cursors[sha1])
+    {
+        SpiceSimulateCursor.unknown_cursors[sha1] = curdata;
+        console.log('Unknown cursor.  Simulation required.  To avoid simulation for this cursor, create and include a custom javascript file, and add the following line:');
+        console.log('SpiceCursorSimulator.add_cursor("' + sha1 + '"), "<your filename here>.cur");');
+        console.log('And then run following command, redirecting output into <your filename here>.cur:');
+        console.log('php -r "echo urldecode(\'' + curdata + '\');"');
+    }
+},
+
+simulate_cursor: function (spicecursor, cursor, screen, pngstr)
+{
+    var cursor_sha = hex_sha1(pngstr + ' ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y);
+    if (typeof SpiceSimulateCursor.cursors != 'undefined')
+        if (typeof SpiceSimulateCursor.cursors[cursor_sha] != 'undefined')
+        {
+            var curstr = 'url(' + SpiceSimulateCursor.cursors[cursor_sha] + '), default';
+            screen.style.cursor = curstr;
+        }
+
+    if (window.getComputedStyle(screen, null).cursor == 'auto')
+    {
+        SpiceSimulateCursor.unknown_cursor(cursor_sha,
+            SpiceSimulateCursor.create_icondir(cursor.header.width, cursor.header.height,
+            cursor.data.byteLength, cursor.header.hot_spot_x, cursor.header.hot_spot_y) + pngstr);
+
+        document.getElementById(spicecursor.parent.screen_id).style.cursor = 'none';
+        if (! spicecursor.spice_simulated_cursor)
+        {
+            spicecursor.spice_simulated_cursor = document.createElement('img');
+
+            spicecursor.spice_simulated_cursor.style.position = 'absolute';
+            spicecursor.spice_simulated_cursor.style.display = 'none';
+            spicecursor.spice_simulated_cursor.style.overflow = 'hidden';
+
+            spicecursor.spice_simulated_cursor.spice_screen = document.getElementById(spicecursor.parent.screen_id);
+
+            spicecursor.spice_simulated_cursor.addEventListener('mousemove', SpiceSimulateCursor.handle_sim_mousemove);
+
+            spicecursor.spice_simulated_cursor.spice_screen.appendChild(spicecursor.spice_simulated_cursor);
+        }
+
+        spicecursor.spice_simulated_cursor.src = 'data:image/png,' + pngstr;
+
+        spicecursor.spice_simulated_cursor.spice_hot_x = cursor.header.hot_spot_x;
+        spicecursor.spice_simulated_cursor.spice_hot_y = cursor.header.hot_spot_y;
+
+        spicecursor.spice_simulated_cursor.style.pointerEvents = "none";
+    }
+    else
+    {
+        if (spicecursor.spice_simulated_cursor)
+        {
+            spicecursor.spice_simulated_cursor.spice_screen.removeChild(spicecursor.spice_simulated_cursor);
+            delete spicecursor.spice_simulated_cursor;
+        }
+    }
+},
+
+handle_sim_mousemove: function(e)
+{
+    var retval;
+    var f = SpiceSimulateCursor.duplicate_mouse_event(e, this.spice_screen);
+    return this.spice_screen.dispatchEvent(f);
+},
+
+duplicate_mouse_event: function(e, target)
+{
+    var evt = document.createEvent("mouseevent");
+    evt.initMouseEvent(e.type, true, true, e.view, e.detail,
+        e.screenX, e.screenY, e.clientX, e.clientY,
+        e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
+    return evt;
+},
+
+ICONDIR: function ()
+{
+},
+
+ICONDIRENTRY: function(width, height, bytes, hot_x, hot_y)
+{
+    this.width = width;
+    this.height = height;
+    this.bytes = bytes;
+    this.hot_x = hot_x;
+    this.hot_y = hot_y;
+},
+
+
+create_icondir: function (width, height, bytes, hot_x, hot_y)
+{
+    var i;
+    var header = new SpiceSimulateCursor.ICONDIR();
+    var entry = new SpiceSimulateCursor.ICONDIRENTRY(width, height, bytes, hot_x, hot_y);
+
+    var mb = new ArrayBuffer(header.buffer_size() + entry.buffer_size());
+    var at = header.to_buffer(mb);
+    at = entry.to_buffer(mb, at);
+
+    var u8 = new Uint8Array(mb);
+    var str = "";
+    for (i = 0; i < at; i++)
+    {
+        str += "%";
+        if (u8[i] < 16)
+            str += "0";
+        str += u8[i].toString(16);
+    }
+    return str;
+},
+
+};
+
+SpiceSimulateCursor.ICONDIR.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint16(at, 0, true); at += 2;
+        dv.setUint16(at, 2, true); at += 2;
+        dv.setUint16(at, 1, true); at += 2;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 6;
+    }
+};
+
+SpiceSimulateCursor.ICONDIRENTRY.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint8(at, this.width); at++;
+        dv.setUint8(at, this.height); at++;
+        dv.setUint8(at, 0); at++;  /* color palette count, unused */
+        dv.setUint8(at, 0); at++;  /* reserved */
+        dv.setUint16(at, this.hot_x, true); at += 2;
+        dv.setUint16(at, this.hot_y, true); at += 2;
+        dv.setUint32(at, this.bytes, true); at += 4;
+        dv.setUint32(at, at + 4, true); at += 4;  /* Offset to bytes */
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 16;
+    }
+};
+
+export { SpiceSimulateCursor };
diff -pruN 0.1.7-5/src/spicearraybuffer.js 0.2.2-0ubuntu3/src/spicearraybuffer.js
--- 0.1.7-5/src/spicearraybuffer.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/spicearraybuffer.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,58 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  SpiceArrayBufferSlice
+**    This function is a work around for IE 10, which has no slice()
+**    method in it's subclass.
+**--------------------------------------------------------------------------*/
+function SpiceArrayBufferSlice(start, end)
+{
+    start = start || 0;
+    end = end || this.byteLength;
+    if (end < 0)
+        end = this.byteLength + end;
+    if (start < 0)
+        start = this.byteLength + start;
+    if (start < 0)
+        start = 0;
+    if (end < 0)
+        end = 0;
+    if (end > this.byteLength)
+        end = this.byteLength;
+    if (start > end)
+        start = end;
+
+    var ret = new ArrayBuffer(end - start);
+    var in1 = new Uint8Array(this, start, end - start);
+    var out = new Uint8Array(ret);
+    var i;
+
+    for (i = 0; i < end - start; i++)
+        out[i] = in1[i];
+
+    return ret;
+}
+
+if (! ArrayBuffer.prototype.slice)
+{
+    ArrayBuffer.prototype.slice = SpiceArrayBufferSlice;
+    console.log("WARNING:  ArrayBuffer.slice() is missing; we are extending ArrayBuffer to compensate");
+}
diff -pruN 0.1.7-5/src/spiceconn.js 0.2.2-0ubuntu3/src/spiceconn.js
--- 0.1.7-5/src/spiceconn.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/spiceconn.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,526 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  SpiceConn
+**      This is the base Javascript class for establishing and
+**  managing a connection to a Spice Server.
+**  It is used to provide core functionality to the Spice main,
+**  display, inputs, and cursor channels.  See main.js for
+**  usage.
+**--------------------------------------------------------------------------*/
+
+import { Constants } from './enums.js';
+import { SpiceWireReader } from './wire.js';
+import {
+  SpiceLinkHeader,
+  SpiceLinkMess,
+  SpiceLinkReply,
+  SpiceLinkAuthTicket,
+  SpiceLinkAuthReply,
+  SpiceMiniData,
+  SpiceMsgcDisplayInit,
+  SpiceMsgSetAck,
+  SpiceMsgcAckSync,
+  SpiceMsgNotify,
+} from './spicemsg.js';
+import { DEBUG } from './utils.js';
+import * as Webm from './webm.js';
+import { rsa_encrypt } from './ticket.js';
+
+function SpiceConn(o)
+{
+    if (o === undefined || o.uri === undefined || ! o.uri)
+        throw new Error("You must specify a uri");
+
+    this.ws = new WebSocket(o.uri, 'binary');
+
+    if (! this.ws.binaryType)
+        throw new Error("WebSocket doesn't support binaryType.  Try a different browser.");
+
+    this.connection_id = o.connection_id !== undefined ? o.connection_id : 0;
+    this.type = o.type !== undefined ? o.type : Constants.SPICE_CHANNEL_MAIN;
+    this.chan_id = o.chan_id !== undefined ? o.chan_id : 0;
+    if (o.parent !== undefined)
+    {
+        this.parent = o.parent;
+        this.message_id = o.parent.message_id;
+        this.password = o.parent.password;
+    }
+    if (o.screen_id !== undefined)
+        this.screen_id = o.screen_id;
+    if (o.dump_id !== undefined)
+        this.dump_id = o.dump_id;
+    if (o.message_id !== undefined)
+        this.message_id = o.message_id;
+    if (o.password !== undefined)
+        this.password = o.password;
+    if (o.onerror !== undefined)
+        this.onerror = o.onerror;
+    if (o.onsuccess !== undefined)
+        this.onsuccess = o.onsuccess;
+    if (o.onagent !== undefined)
+        this.onagent = o.onagent;
+
+    this.state = "connecting";
+    this.ws.parent = this;
+    this.wire_reader = new SpiceWireReader(this, this.process_inbound);
+    this.messages_sent = 0;
+    this.warnings = [];
+
+    this.ws.addEventListener('open', function(e) {
+        DEBUG > 0 && console.log(">> WebSockets.onopen");
+        DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type);
+
+        /***********************************************************************
+        **          WHERE IT ALL REALLY BEGINS
+        ***********************************************************************/
+        this.parent.send_hdr();
+        this.parent.wire_reader.request(SpiceLinkHeader.prototype.buffer_size());
+        this.parent.state = "start";
+    });
+    this.ws.addEventListener('error', function(e) {
+        if ('url' in e.target) {
+            this.parent.log_err("WebSocket error: Can't connect to websocket on URL: " + e.target.url);
+        }
+        this.parent.report_error(e);
+    });
+    this.ws.addEventListener('close', function(e) {
+        DEBUG > 0 && console.log(">> WebSockets.onclose");
+        DEBUG > 0 && console.log("id " + this.parent.connection_id +"; type " + this.parent.type);
+        DEBUG > 0 && console.log(e);
+        if (this.parent.state != "closing" && this.parent.state != "error" && this.parent.onerror !== undefined)
+        {
+            var e;
+            if (this.parent.state == "connecting")
+                e = new Error("Connection refused.");
+            else if (this.parent.state == "start" || this.parent.state == "link")
+                e = new Error("Unexpected protocol mismatch.");
+            else if (this.parent.state == "ticket")
+                e = new Error("Bad password.");
+            else
+                e = new Error("Unexpected close while " + this.parent.state);
+
+            this.parent.onerror(e);
+            this.parent.log_err(e.toString());
+        }
+    });
+
+    if (this.ws.readyState == 2 || this.ws.readyState == 3)
+        throw new Error("Unable to connect to " + o.uri);
+
+    this.timeout = window.setTimeout(spiceconn_timeout, Constants.SPICE_CONNECT_TIMEOUT, this);
+}
+
+SpiceConn.prototype =
+{
+    send_hdr : function ()
+    {
+        var hdr = new SpiceLinkHeader;
+        var msg = new SpiceLinkMess;
+
+        msg.connection_id = this.connection_id;
+        msg.channel_type = this.type;
+        msg.channel_id = this.chan_id;
+
+        msg.common_caps.push(
+            (1 << Constants.SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION) |
+            (1 << Constants.SPICE_COMMON_CAP_MINI_HEADER)
+            );
+
+        if (msg.channel_type == Constants.SPICE_CHANNEL_PLAYBACK)
+        {
+            var caps = 0;
+            if ('MediaSource' in window && MediaSource.isTypeSupported(Webm.Constants.SPICE_PLAYBACK_CODEC))
+                caps |= (1 << Constants.SPICE_PLAYBACK_CAP_OPUS);
+            msg.channel_caps.push(caps);
+        }
+        else if (msg.channel_type == Constants.SPICE_CHANNEL_MAIN)
+        {
+            msg.channel_caps.push(
+                (1 << Constants.SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)
+            );
+        }
+        else if (msg.channel_type == Constants.SPICE_CHANNEL_DISPLAY)
+        {
+            var caps =  (1 << Constants.SPICE_DISPLAY_CAP_SIZED_STREAM) |
+                        (1 << Constants.SPICE_DISPLAY_CAP_STREAM_REPORT) |
+                        (1 << Constants.SPICE_DISPLAY_CAP_MULTI_CODEC) |
+                        (1 << Constants.SPICE_DISPLAY_CAP_CODEC_MJPEG);
+            if ('MediaSource' in window && MediaSource.isTypeSupported(Webm.Constants.SPICE_VP8_CODEC))
+                caps |= (1 << Constants.SPICE_DISPLAY_CAP_CODEC_VP8);
+            msg.channel_caps.push(caps);
+        }
+
+        hdr.size = msg.buffer_size();
+
+        var mb = new ArrayBuffer(hdr.buffer_size() + msg.buffer_size());
+        hdr.to_buffer(mb);
+        msg.to_buffer(mb, hdr.buffer_size());
+
+        DEBUG > 1 && console.log("Sending header:");
+        DEBUG > 2 && hexdump_buffer(mb);
+        this.ws.send(mb);
+    },
+
+    send_ticket: function(ticket)
+    {
+        var hdr = new SpiceLinkAuthTicket();
+        hdr.auth_mechanism = Constants.SPICE_COMMON_CAP_AUTH_SPICE;
+        // FIXME - we need to implement RSA to make this work right
+        hdr.encrypted_data = ticket;
+        var mb = new ArrayBuffer(hdr.buffer_size());
+
+        hdr.to_buffer(mb);
+        DEBUG > 1 && console.log("Sending ticket:");
+        DEBUG > 2 && hexdump_buffer(mb);
+        this.ws.send(mb);
+    },
+
+    send_msg: function(msg)
+    {
+        var mb = new ArrayBuffer(msg.buffer_size());
+        msg.to_buffer(mb);
+        this.messages_sent++;
+        DEBUG > 0 && console.log(">> hdr " + this.channel_type() + " type " + msg.type + " size " + mb.byteLength);
+        DEBUG > 2 && hexdump_buffer(mb);
+        this.ws.send(mb);
+    },
+
+    process_inbound: function(mb, saved_header)
+    {
+        DEBUG > 2 && console.log(this.type + ": processing message of size " + mb.byteLength + "; state is " + this.state);
+        if (this.state == "ready")
+        {
+            if (saved_header == undefined)
+            {
+                var msg = new SpiceMiniData(mb);
+
+                if (msg.type > 500)
+                {
+                    if (DEBUG > 0)
+                    {
+                        alert("Something has gone very wrong; we think we have message of type " + msg.type);
+                        debugger;
+                    }
+                }
+
+                if (msg.size == 0)
+                {
+                    this.process_message(msg);
+                    this.wire_reader.request(SpiceMiniData.prototype.buffer_size());
+                }
+                else
+                {
+                    this.wire_reader.request(msg.size);
+                    this.wire_reader.save_header(msg);
+                }
+            }
+            else
+            {
+                saved_header.data = mb;
+                this.process_message(saved_header);
+                this.wire_reader.request(SpiceMiniData.prototype.buffer_size());
+                this.wire_reader.save_header(undefined);
+            }
+        }
+
+        else if (this.state == "start")
+        {
+            this.reply_hdr = new SpiceLinkHeader(mb);
+            if (this.reply_hdr.magic != Constants.SPICE_MAGIC)
+            {
+                this.state = "error";
+                var e = new Error('Error: magic mismatch: ' + this.reply_hdr.magic);
+                this.report_error(e);
+            }
+            else
+            {
+                // FIXME - Determine major/minor version requirements
+                this.wire_reader.request(this.reply_hdr.size);
+                this.state = "link";
+            }
+        }
+
+        else if (this.state == "link")
+        {
+            this.reply_link = new SpiceLinkReply(mb);
+             // FIXME - Screen the caps - require minihdr at least, right?
+            if (this.reply_link.error)
+            {
+                this.state = "error";
+                var e = new Error('Error: reply link error ' + this.reply_link.error);
+                this.report_error(e);
+            }
+            else
+            {
+                this.send_ticket(rsa_encrypt(this.reply_link.pub_key, this.password + String.fromCharCode(0)));
+                this.state = "ticket";
+                this.wire_reader.request(SpiceLinkAuthReply.prototype.buffer_size());
+            }
+        }
+
+        else if (this.state == "ticket")
+        {
+            this.auth_reply = new SpiceLinkAuthReply(mb);
+            if (this.auth_reply.auth_code == Constants.SPICE_LINK_ERR_OK)
+            {
+                DEBUG > 0 && console.log(this.type + ': Connected');
+
+                if (this.type == Constants.SPICE_CHANNEL_DISPLAY)
+                {
+                    // FIXME - pixmap and glz dictionary config info?
+                    var dinit = new SpiceMsgcDisplayInit();
+                    var reply = new SpiceMiniData();
+                    reply.build_msg(Constants.SPICE_MSGC_DISPLAY_INIT, dinit);
+                    DEBUG > 0 && console.log("Request display init");
+                    this.send_msg(reply);
+                }
+                this.state = "ready";
+                this.wire_reader.request(SpiceMiniData.prototype.buffer_size());
+                if (this.timeout)
+                {
+                    window.clearTimeout(this.timeout);
+                    delete this.timeout;
+                }
+            }
+            else
+            {
+                this.state = "error";
+                if (this.auth_reply.auth_code == Constants.SPICE_LINK_ERR_PERMISSION_DENIED)
+                {
+                    var e = new Error("Permission denied.");
+                }
+                else
+                {
+                    var e = new Error("Unexpected link error " + this.auth_reply.auth_code);
+                }
+                this.report_error(e);
+            }
+        }
+    },
+
+    process_common_messages : function(msg)
+    {
+        if (msg.type == Constants.SPICE_MSG_SET_ACK)
+        {
+            var ack = new SpiceMsgSetAck(msg.data);
+            // FIXME - what to do with generation?
+            this.ack_window = ack.window;
+            DEBUG > 1 && console.log(this.type + ": set ack to " + ack.window);
+            this.msgs_until_ack = this.ack_window;
+            var ackack = new SpiceMsgcAckSync(ack);
+            var reply = new SpiceMiniData();
+            reply.build_msg(Constants.SPICE_MSGC_ACK_SYNC, ackack);
+            this.send_msg(reply);
+            return true;
+        }
+
+        if (msg.type == Constants.SPICE_MSG_PING)
+        {
+            DEBUG > 1 && console.log("ping!");
+            var pong = new SpiceMiniData;
+            pong.type = Constants.SPICE_MSGC_PONG;
+            if (msg.data)
+            {
+                pong.data = msg.data.slice(0, 12);
+            }
+            pong.size = pong.buffer_size();
+            this.send_msg(pong);
+            return true;
+        }
+
+        if (msg.type == Constants.SPICE_MSG_NOTIFY)
+        {
+            // FIXME - Visibility + what
+            var notify = new SpiceMsgNotify(msg.data);
+            if (notify.severity == Constants.SPICE_NOTIFY_SEVERITY_ERROR)
+                this.log_err(notify.message);
+            else if (notify.severity == Constants.SPICE_NOTIFY_SEVERITY_WARN )
+                this.log_warn(notify.message);
+            else
+                this.log_info(notify.message);
+            return true;
+        }
+
+        return false;
+
+    },
+
+    process_message: function(msg)
+    {
+        var rc;
+        var start = Date.now();
+        DEBUG > 0 && console.log("<< hdr " + this.channel_type() + " type " + msg.type + " size " + (msg.data && msg.data.byteLength));
+        rc = this.process_common_messages(msg);
+        if (! rc)
+        {
+            if (this.process_channel_message)
+            {
+                rc = this.process_channel_message(msg);
+                if (! rc)
+                    this.log_warn(this.channel_type() + ": Unknown message type " + msg.type + "!");
+            }
+            else
+                this.log_err(this.channel_type() + ": No message handlers for this channel; message " + msg.type);
+        }
+
+        if (this.msgs_until_ack !== undefined && this.ack_window)
+        {
+            this.msgs_until_ack--;
+            if (this.msgs_until_ack <= 0)
+            {
+                this.msgs_until_ack = this.ack_window;
+                var ack = new SpiceMiniData();
+                ack.type = Constants.SPICE_MSGC_ACK;
+                this.send_msg(ack);
+                DEBUG > 1 && console.log(this.type + ": sent ack");
+            }
+        }
+
+        var delta = Date.now() - start;
+        if (DEBUG > 0 || delta > Webm.Constants.GAP_DETECTION_THRESHOLD)
+            console.log("delta " + this.channel_type() + ":" + msg.type + " " + delta);
+        return rc;
+    },
+
+    channel_type: function()
+    {
+        if (this.type == Constants.SPICE_CHANNEL_MAIN)
+            return "main";
+        else if (this.type == Constants.SPICE_CHANNEL_DISPLAY)
+            return "display";
+        else if (this.type == Constants.SPICE_CHANNEL_INPUTS)
+            return "inputs";
+        else if (this.type == Constants.SPICE_CHANNEL_CURSOR)
+            return "cursor";
+        else if (this.type == Constants.SPICE_CHANNEL_PLAYBACK)
+            return "playback";
+        else if (this.type == Constants.SPICE_CHANNEL_RECORD)
+            return "record";
+        else if (this.type == Constants.SPICE_CHANNEL_TUNNEL)
+            return "tunnel";
+        else if (this.type == Constants.SPICE_CHANNEL_SMARTCARD)
+            return "smartcard";
+        else if (this.type == Constants.SPICE_CHANNEL_USBREDIR)
+            return "usbredir";
+        else if (this.type == Constants.SPICE_CHANNEL_PORT)
+            return "port";
+        else if (this.type == Constants.SPICE_CHANNEL_WEBDAV)
+            return "webdav";
+        return "unknown-" + this.type;
+
+    },
+
+    log_info: function()
+    {
+        var msg = Array.prototype.join.call(arguments, " ");
+        console.log(msg);
+        if (this.message_id)
+        {
+            var p = document.createElement("p");
+            p.appendChild(document.createTextNode(msg));
+            p.className += "spice-message-info";
+            document.getElementById(this.message_id).appendChild(p);
+        }
+    },
+
+    log_warn: function()
+    {
+        var msg = Array.prototype.join.call(arguments, " ");
+        console.log("WARNING: " + msg);
+        if (this.message_id)
+        {
+            var p = document.createElement("p");
+            p.appendChild(document.createTextNode(msg));
+            p.className += "spice-message-warning";
+            document.getElementById(this.message_id).appendChild(p);
+        }
+    },
+
+    log_err: function()
+    {
+        var msg = Array.prototype.join.call(arguments, " ");
+        console.log("ERROR: " + msg);
+        if (this.message_id)
+        {
+            var p = document.createElement("p");
+            p.appendChild(document.createTextNode(msg));
+            p.className += "spice-message-error";
+            document.getElementById(this.message_id).appendChild(p);
+        }
+    },
+
+    known_unimplemented: function(type, msg)
+    {
+        if ( (!this.warnings[type]) || DEBUG > 1)
+        {
+            var str = "";
+            if (DEBUG <= 1)
+                str = " [ further notices suppressed ]";
+            this.log_warn("Unimplemented function " + type + "(" + msg + ")" + str);
+            this.warnings[type] = true;
+        }
+    },
+
+    report_error: function(e)
+    {
+        this.log_err(e.toString());
+        if (this.onerror != undefined)
+            this.onerror(e);
+        else
+            throw(e);
+    },
+
+    report_success: function(m)
+    {
+        if (this.onsuccess != undefined)
+            this.onsuccess(m);
+    },
+
+    cleanup: function()
+    {
+        if (this.timeout)
+        {
+            window.clearTimeout(this.timeout);
+            delete this.timeout;
+        }
+        if (this.ws)
+        {
+            this.ws.close();
+            this.ws = undefined;
+        }
+    },
+
+    handle_timeout: function()
+    {
+        var e = new Error("Connection timed out.");
+        this.report_error(e);
+    },
+}
+
+function spiceconn_timeout(sc)
+{
+    SpiceConn.prototype.handle_timeout.call(sc);
+}
+
+export {
+  SpiceConn,
+};
diff -pruN 0.1.7-5/src/spicedataview.js 0.2.2-0ubuntu3/src/spicedataview.js
--- 0.1.7-5/src/spicedataview.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/spicedataview.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,124 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  SpiceDataView
+** FIXME FIXME
+**    This is used because Firefox does not have DataView yet.
+**    We should use DataView if we have it, because it *has* to
+**    be faster than this code
+**--------------------------------------------------------------------------*/
+function SpiceDataView(buffer, byteOffset, byteLength)
+{
+    if (byteOffset !== undefined)
+    {
+        if (byteLength !== undefined)
+            this.u8 = new Uint8Array(buffer, byteOffset, byteLength);
+        else
+            this.u8 = new Uint8Array(buffer, byteOffset);
+    }
+    else
+        this.u8 = new Uint8Array(buffer);
+};
+
+SpiceDataView.prototype = {
+    getUint8:  function(byteOffset)
+    {
+        return this.u8[byteOffset];
+    },
+    getUint16:  function(byteOffset, littleEndian)
+    {
+        var low = 1, high = 0;
+        if (littleEndian)
+        {
+            low = 0;
+            high = 1;
+        }
+
+        return (this.u8[byteOffset + high] << 8) | this.u8[byteOffset + low];
+    },
+    getUint32:  function(byteOffset, littleEndian)
+    {
+        var low = 2, high = 0;
+        if (littleEndian)
+        {
+            low = 0;
+            high = 2;
+        }
+
+        return (this.getUint16(byteOffset + high, littleEndian) << 16) |
+                this.getUint16(byteOffset + low, littleEndian);
+    },
+    getUint64: function (byteOffset, littleEndian)
+    {
+        var low = 4, high = 0;
+        if (littleEndian)
+        {
+            low = 0;
+            high = 4;
+        }
+
+        return (this.getUint32(byteOffset + high, littleEndian) << 32) |
+                this.getUint32(byteOffset + low, littleEndian);
+    },
+    setUint8:  function(byteOffset, b)
+    {
+        this.u8[byteOffset] = (b & 0xff);
+    },
+    setUint16:  function(byteOffset, i, littleEndian)
+    {
+        var low = 1, high = 0;
+        if (littleEndian)
+        {
+            low = 0;
+            high = 1;
+        }
+        this.u8[byteOffset + high] = (i & 0xffff) >> 8;
+        this.u8[byteOffset + low]  = (i & 0x00ff);
+    },
+    setUint32:  function(byteOffset, w, littleEndian)
+    {
+        var low = 2, high = 0;
+        if (littleEndian)
+        {
+            low = 0;
+            high = 2;
+        }
+
+        this.setUint16(byteOffset + high, (w & 0xffffffff) >> 16, littleEndian);
+        this.setUint16(byteOffset + low,  (w & 0x0000ffff), littleEndian);
+    },
+    setUint64:  function(byteOffset, w, littleEndian)
+    {
+        var low = 4, high = 0;
+        if (littleEndian)
+        {
+            low = 0;
+            high = 4;
+        }
+
+        this.setUint32(byteOffset + high, (w & 0xffffffffffffffff) >> 32, littleEndian);
+        this.setUint32(byteOffset + low,  (w & 0x00000000ffffffff), littleEndian);
+    },
+}
+
+export {
+  SpiceDataView,
+};
diff -pruN 0.1.7-5/src/spicemsg.js 0.2.2-0ubuntu3/src/spicemsg.js
--- 0.1.7-5/src/spicemsg.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/spicemsg.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,1371 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  Spice messages
+**      This file contains classes for passing messages to and from
+**  a spice server.  This file should arguably be generated from
+**  spice.proto, but it was instead put together by hand.
+**--------------------------------------------------------------------------*/
+
+import { Constants } from './enums.js';
+import { SpiceDataView } from './spicedataview.js';
+import { create_rsa_from_mb } from './ticket.js';
+import {
+  SpiceChannelId,
+  SpiceRect,
+  SpiceClip,
+  SpiceCopy,
+  SpiceFill,
+  SpicePoint,
+  SpiceSurface,
+  SpicePoint16,
+  SpiceCursor,
+} from './spicetype.js';
+import {
+  keycode_to_start_scan,
+  keycode_to_end_scan,
+} from './utils.js';
+
+function SpiceLinkHeader(a, at)
+{
+    this.magic = Constants.SPICE_MAGIC;
+    this.major_version = Constants.SPICE_VERSION_MAJOR;
+    this.minor_version = Constants.SPICE_VERSION_MINOR;
+    this.size = 0;
+    if (a !== undefined)
+        this.from_buffer(a, at);
+}
+
+SpiceLinkHeader.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.magic = "";
+        for (var i = 0; i < 4; i++)
+            this.magic += String.fromCharCode(dv.getUint8(at + i));
+        at += 4;
+
+        this.major_version = dv.getUint32(at, true); at += 4;
+        this.minor_version = dv.getUint32(at, true); at += 4;
+        this.size = dv.getUint32(at, true); at += 4;
+    },
+
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        for (var i = 0; i < 4; i++)
+            dv.setUint8(at + i, this.magic.charCodeAt(i));
+        at += 4;
+
+        dv.setUint32(at, this.major_version, true); at += 4;
+        dv.setUint32(at, this.minor_version, true); at += 4;
+        dv.setUint32(at, this.size, true); at += 4;
+    },
+    buffer_size: function()
+    {
+        return 16;
+    },
+}
+
+function SpiceLinkMess(a, at)
+{
+    this.connection_id = 0;
+    this.channel_type = 0;
+    this.channel_id = 0;
+    this.common_caps = [];
+    this.channel_caps = [];
+
+    if (a !== undefined)
+        this.from_buffer(a, at);
+}
+
+SpiceLinkMess.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var i;
+        var orig_at = at;
+        var dv = new SpiceDataView(a);
+        this.connection_id = dv.getUint32(at, true); at += 4;
+        this.channel_type = dv.getUint8(at, true); at++;
+        this.channel_id = dv.getUint8(at, true); at++;
+        var num_common_caps = dv.getUint32(at, true); at += 4;
+        var num_channel_caps  = dv.getUint32(at, true); at += 4;
+        var caps_offset = dv.getUint32(at, true); at += 4;
+
+        at = orig_at + caps_offset;
+        this.common_caps = [];
+        for (i = 0; i < num_common_caps; i++)
+        {
+            this.common_caps.unshift(dv.getUint32(at, true)); at += 4;
+        }
+
+        this.channel_caps = [];
+        for (i = 0; i < num_channel_caps; i++)
+        {
+            this.channel_caps.unshift(dv.getUint32(at, true)); at += 4;
+        }
+    },
+
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var orig_at = at;
+        var i;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.connection_id, true); at += 4;
+        dv.setUint8(at, this.channel_type, true); at++;
+        dv.setUint8(at, this.channel_id, true); at++;
+        dv.setUint32(at, this.common_caps.length, true); at += 4;
+        dv.setUint32(at, this.channel_caps.length, true); at += 4;
+        dv.setUint32(at, (at - orig_at) + 4, true); at += 4;
+
+        for (i = 0; i < this.common_caps.length; i++)
+        {
+            dv.setUint32(at, this.common_caps[i], true); at += 4;
+        }
+
+        for (i = 0; i < this.channel_caps.length; i++)
+        {
+            dv.setUint32(at, this.channel_caps[i], true); at += 4;
+        }
+    },
+    buffer_size: function()
+    {
+        return 18 + (4 * this.common_caps.length) + (4 * this.channel_caps.length);
+    }
+}
+
+function SpiceLinkReply(a, at)
+{
+    this.error = 0;
+    this.pub_key = undefined;
+    this.common_caps = [];
+    this.channel_caps = [];
+
+    if (a !== undefined)
+        this.from_buffer(a, at);
+}
+
+SpiceLinkReply.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var i;
+        var orig_at = at;
+        var dv = new SpiceDataView(a);
+        this.error = dv.getUint32(at, true); at += 4;
+
+        this.pub_key = create_rsa_from_mb(a, at);
+        at += Constants.SPICE_TICKET_PUBKEY_BYTES;
+
+        var num_common_caps = dv.getUint32(at, true); at += 4;
+        var num_channel_caps  = dv.getUint32(at, true); at += 4;
+        var caps_offset = dv.getUint32(at, true); at += 4;
+
+        at = orig_at + caps_offset;
+        this.common_caps = [];
+        for (i = 0; i < num_common_caps; i++)
+        {
+            this.common_caps.unshift(dv.getUint32(at, true)); at += 4;
+        }
+
+        this.channel_caps = [];
+        for (i = 0; i < num_channel_caps; i++)
+        {
+            this.channel_caps.unshift(dv.getUint32(at, true)); at += 4;
+        }
+    },
+}
+
+function SpiceLinkAuthTicket(a, at)
+{
+    this.auth_mechanism = 0;
+    this.encrypted_data = undefined;
+}
+
+SpiceLinkAuthTicket.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var i;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.auth_mechanism, true); at += 4;
+        for (i = 0; i < Constants.SPICE_TICKET_KEY_PAIR_LENGTH / 8; i++)
+        {
+            if (this.encrypted_data && i < this.encrypted_data.length)
+                dv.setUint8(at, this.encrypted_data[i], true);
+            else
+                dv.setUint8(at, 0, true);
+            at++;
+        }
+    },
+    buffer_size: function()
+    {
+        return 4 + (Constants.SPICE_TICKET_KEY_PAIR_LENGTH / 8);
+    }
+}
+
+function SpiceLinkAuthReply(a, at)
+{
+    this.auth_code = 0;
+    if (a !== undefined)
+        this.from_buffer(a, at);
+}
+
+SpiceLinkAuthReply.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.auth_code = dv.getUint32(at, true); at += 4;
+    },
+    buffer_size: function()
+    {
+        return 4;
+    }
+}
+
+function SpiceMiniData(a, at)
+{
+    this.type = 0;
+    this.size = 0;
+    this.data = undefined;
+    if (a !== undefined)
+        this.from_buffer(a, at);
+}
+
+SpiceMiniData.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var i;
+        var dv = new SpiceDataView(a);
+        this.type = dv.getUint16(at, true); at += 2;
+        this.size = dv.getUint32(at, true); at += 4;
+        if (a.byteLength > at)
+        {
+            this.data = a.slice(at);
+            at += this.data.byteLength;
+        }
+    },
+    to_buffer : function(a, at)
+    {
+        at = at || 0;
+        var i;
+        var dv = new SpiceDataView(a);
+        dv.setUint16(at, this.type, true); at += 2;
+        dv.setUint32(at, this.data ? this.data.byteLength : 0, true); at += 4;
+        if (this.data && this.data.byteLength > 0)
+        {
+            var u8arr = new Uint8Array(this.data);
+            for (i = 0; i < u8arr.length; i++, at++)
+                dv.setUint8(at, u8arr[i], true);
+        }
+    },
+    build_msg : function(in_type,  extra)
+    {
+        this.type = in_type;
+        this.size = extra.buffer_size();
+        this.data = new ArrayBuffer(this.size);
+        extra.to_buffer(this.data);
+    },
+    buffer_size: function()
+    {
+        if (this.data)
+            return 6 + this.data.byteLength;
+        else
+            return 6;
+    },
+}
+
+function SpiceMsgChannels(a, at)
+{
+    this.num_of_channels = 0;
+    this.channels = [];
+    if (a !== undefined)
+        this.from_buffer(a, at);
+}
+
+SpiceMsgChannels.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var i;
+        var dv = new SpiceDataView(a);
+        this.num_of_channels = dv.getUint32(at, true); at += 4;
+        for (i = 0; i < this.num_of_channels; i++)
+        {
+            var chan = new SpiceChannelId();
+            at = chan.from_dv(dv, at, a);
+            this.channels.push(chan);
+        }
+    },
+}
+
+function SpiceMsgMainInit(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgMainInit.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.session_id = dv.getUint32(at, true); at += 4;
+        this.display_channels_hint = dv.getUint32(at, true); at += 4;
+        this.supported_mouse_modes = dv.getUint32(at, true); at += 4;
+        this.current_mouse_mode = dv.getUint32(at, true); at += 4;
+        this.agent_connected = dv.getUint32(at, true); at += 4;
+        this.agent_tokens = dv.getUint32(at, true); at += 4;
+        this.multi_media_time = dv.getUint32(at, true); at += 4;
+        this.ram_hint = dv.getUint32(at, true); at += 4;
+    },
+}
+
+function SpiceMsgMainMouseMode(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgMainMouseMode.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.supported_modes = dv.getUint16(at, true); at += 2;
+        this.current_mode = dv.getUint16(at, true); at += 2;
+    },
+}
+
+function SpiceMsgMainAgentData(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgMainAgentData.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.protocol = dv.getUint32(at, true); at += 4;
+        this.type = dv.getUint32(at, true); at += 4;
+        this.opaque = dv.getUint64(at, true); at += 8;
+        this.size = dv.getUint32(at, true); at += 4;
+        if (a.byteLength > at)
+        {
+            this.data = a.slice(at);
+            at += this.data.byteLength;
+        }
+    }
+}
+
+function SpiceMsgMainAgentTokens(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgMainAgentTokens.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.num_tokens = dv.getUint32(at, true); at += 4;
+    },
+}
+
+function SpiceMsgSetAck(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgSetAck.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.generation = dv.getUint32(at, true); at += 4;
+        this.window = dv.getUint32(at, true); at += 4;
+    },
+}
+
+function SpiceMsgcAckSync(ack)
+{
+    this.generation = ack.generation;
+}
+
+SpiceMsgcAckSync.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.generation, true); at += 4;
+    },
+    buffer_size: function()
+    {
+        return 4;
+    }
+}
+
+function SpiceMsgcMainMouseModeRequest(mode)
+{
+    this.mode = mode;
+}
+
+SpiceMsgcMainMouseModeRequest.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint16(at, this.mode, true); at += 2;
+    },
+    buffer_size: function()
+    {
+        return 2;
+    }
+}
+
+function SpiceMsgcMainAgentStart(num_tokens)
+{
+    this.num_tokens = num_tokens;
+}
+
+SpiceMsgcMainAgentStart.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.num_tokens, true); at += 4;
+    },
+    buffer_size: function()
+    {
+        return 4;
+    }
+}
+
+function SpiceMsgcMainAgentData(type, data)
+{
+    this.protocol = Constants.VD_AGENT_PROTOCOL;
+    this.type = type;
+    this.opaque = 0;
+    this.size = data.buffer_size();
+    this.data = data;
+}
+
+SpiceMsgcMainAgentData.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.protocol, true); at += 4;
+        dv.setUint32(at, this.type, true); at += 4;
+        dv.setUint64(at, this.opaque, true); at += 8;
+        dv.setUint32(at, this.size, true); at += 4;
+        this.data.to_buffer(a, at);
+    },
+    buffer_size: function()
+    {
+        return 4 + 4 + 8 + 4 + this.data.buffer_size();
+    }
+}
+
+function VDAgentAnnounceCapabilities(request, caps)
+{
+    if (caps)
+    {
+        this.request = request;
+        this.caps = caps;
+    }
+    else
+        this.from_buffer(request);
+}
+
+VDAgentAnnounceCapabilities.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.request, true); at += 4;
+        dv.setUint32(at, this.caps, true); at += 4;
+    },
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.request = dv.getUint32(at, true); at += 4;
+        this.caps = dv.getUint32(at, true); at += 4;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 8;
+    }
+}
+
+function VDAgentMonitorsConfig(flags, width, height, depth, x, y)
+{
+    this.num_mon = 1;
+    this.flags = flags;
+    this.width = width;
+    this.height = height;
+    this.depth = depth;
+    this.x = x;
+    this.y = y;
+}
+
+VDAgentMonitorsConfig.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.num_mon, true); at += 4;
+        dv.setUint32(at, this.flags, true); at += 4;
+        dv.setUint32(at, this.height, true); at += 4;
+        dv.setUint32(at, this.width, true); at += 4;
+        dv.setUint32(at, this.depth, true); at += 4;
+        dv.setUint32(at, this.x, true); at += 4;
+        dv.setUint32(at, this.y, true); at += 4;
+    },
+    buffer_size: function()
+    {
+        return 28;
+    }
+}
+
+function VDAgentFileXferStatusMessage(data, result)
+{
+    if (result)
+    {
+        this.id = data;
+        this.result = result;
+    }
+    else
+        this.from_buffer(data);
+}
+
+VDAgentFileXferStatusMessage.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.id, true); at += 4;
+        dv.setUint32(at, this.result, true); at += 4;
+    },
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.id = dv.getUint32(at, true); at += 4;
+        this.result = dv.getUint32(at, true); at += 4;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 8;
+    }
+}
+
+function VDAgentFileXferStartMessage(id, name, size)
+{
+    this.id = id;
+    this.string = "[vdagent-file-xfer]\n"+"name="+name+"\nsize="+size+"\n";
+}
+
+VDAgentFileXferStartMessage.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.id, true); at += 4;
+        for (var i = 0; i < this.string.length; i++, at++)
+            dv.setUint8(at, this.string.charCodeAt(i));
+    },
+    buffer_size: function()
+    {
+        return 4 + this.string.length + 1;
+    }
+}
+
+function VDAgentFileXferDataMessage(id, size, data)
+{
+    this.id = id;
+    this.size = size;
+    this.data = data;
+}
+
+VDAgentFileXferDataMessage.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.id, true); at += 4;
+        dv.setUint64(at, this.size, true); at += 8;
+        if (this.data && this.data.byteLength > 0)
+        {
+            var u8arr = new Uint8Array(this.data);
+            for (var i = 0; i < u8arr.length; i++, at++)
+                dv.setUint8(at, u8arr[i]);
+        }
+    },
+    buffer_size: function()
+    {
+        return 12 + this.size;
+    }
+}
+
+function SpiceMsgNotify(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgNotify.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var i;
+        var dv = new SpiceDataView(a);
+        this.time_stamp = dv.getUint64(at, true); at += 8;
+        this.severity = dv.getUint32(at, true); at += 4;
+        this.visibility = dv.getUint32(at, true); at += 4;
+        this.what = dv.getUint32(at, true); at += 4;
+        this.message_len = dv.getUint32(at, true); at += 4;
+        this.message = "";
+        for (i = 0; i < this.message_len; i++)
+        {
+            var c = dv.getUint8(at, true); at++;
+            this.message += String.fromCharCode(c);
+        }
+    },
+}
+
+function SpiceMsgcDisplayInit()
+{
+    this.pixmap_cache_id = 1;
+    this.glz_dictionary_id = 0;
+    this.pixmap_cache_size = 10 * 1024 * 1024;
+    this.glz_dictionary_window_size = 0;
+}
+
+SpiceMsgcDisplayInit.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint8(at, this.pixmap_cache_id, true); at++;
+        dv.setUint64(at, this.pixmap_cache_size, true); at += 8;
+        dv.setUint8(at, this.glz_dictionary_id, true); at++;
+        dv.setUint32(at, this.glz_dictionary_window_size, true); at += 4;
+    },
+    buffer_size: function()
+    {
+        return 14;
+    }
+}
+
+function SpiceMsgDisplayBase()
+{
+}
+
+SpiceMsgDisplayBase.prototype =
+{
+    from_dv : function(dv, at, mb)
+    {
+        this.surface_id = dv.getUint32(at, true); at += 4;
+        this.box = new SpiceRect;
+        at = this.box.from_dv(dv, at, mb);
+        this.clip = new SpiceClip;
+        return this.clip.from_dv(dv, at, mb);
+    },
+}
+
+function SpiceMsgDisplayDrawCopy(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayDrawCopy.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.base = new SpiceMsgDisplayBase;
+        at = this.base.from_dv(dv, at, a);
+        this.data = new SpiceCopy;
+        return this.data.from_dv(dv, at, a);
+    },
+}
+
+function SpiceMsgDisplayDrawFill(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayDrawFill.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.base = new SpiceMsgDisplayBase;
+        at = this.base.from_dv(dv, at, a);
+        this.data = new SpiceFill;
+        return this.data.from_dv(dv, at, a);
+    },
+}
+
+function SpiceMsgDisplayCopyBits(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayCopyBits.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.base = new SpiceMsgDisplayBase;
+        at = this.base.from_dv(dv, at, a);
+        this.src_pos = new SpicePoint;
+        return this.src_pos.from_dv(dv, at, a);
+    },
+}
+
+
+function SpiceMsgSurfaceCreate(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgSurfaceCreate.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.surface = new SpiceSurface;
+        return this.surface.from_dv(dv, at, a);
+    },
+}
+
+function SpiceMsgSurfaceDestroy(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgSurfaceDestroy.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.surface_id = dv.getUint32(at, true); at += 4;
+    },
+}
+
+function SpiceMsgInputsInit(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgInputsInit.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.keyboard_modifiers = dv.getUint16(at, true); at += 2;
+        return at;
+    },
+}
+
+function SpiceMsgInputsKeyModifiers(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgInputsKeyModifiers.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.keyboard_modifiers = dv.getUint16(at, true); at += 2;
+        return at;
+    },
+}
+
+function SpiceMsgCursorInit(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgCursorInit.prototype =
+{
+    from_buffer: function(a, at, mb)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.position = new SpicePoint16;
+        at = this.position.from_dv(dv, at, mb);
+        this.trail_length = dv.getUint16(at, true); at += 2;
+        this.trail_frequency = dv.getUint16(at, true); at += 2;
+        this.visible = dv.getUint8(at, true); at ++;
+        this.cursor = new SpiceCursor;
+        return this.cursor.from_dv(dv, at, a);
+    },
+}
+
+function SpiceMsgPlaybackData(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgPlaybackData.prototype =
+{
+    from_buffer: function(a, at, mb)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.time = dv.getUint32(at, true); at += 4;
+        if (a.byteLength > at)
+        {
+            this.data = a.slice(at);
+            at += this.data.byteLength;
+        }
+        return at;
+    },
+}
+
+function SpiceMsgPlaybackMode(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgPlaybackMode.prototype =
+{
+    from_buffer: function(a, at, mb)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.time = dv.getUint32(at, true); at += 4;
+        this.mode = dv.getUint16(at, true); at += 2;
+        if (a.byteLength > at)
+        {
+            this.data = a.slice(at);
+            at += this.data.byteLength;
+        }
+        return at;
+    },
+}
+
+function SpiceMsgPlaybackStart(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgPlaybackStart.prototype =
+{
+    from_buffer: function(a, at, mb)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.channels = dv.getUint32(at, true); at += 4;
+        this.format = dv.getUint16(at, true); at += 2;
+        this.frequency = dv.getUint32(at, true); at += 4;
+        this.time = dv.getUint32(at, true); at += 4;
+        return at;
+    },
+}
+
+
+
+function SpiceMsgCursorSet(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgCursorSet.prototype =
+{
+    from_buffer: function(a, at, mb)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.position = new SpicePoint16;
+        at = this.position.from_dv(dv, at, mb);
+        this.visible = dv.getUint8(at, true); at ++;
+        this.cursor = new SpiceCursor;
+        return this.cursor.from_dv(dv, at, a);
+    },
+}
+
+
+function SpiceMsgcMousePosition(sc, e)
+{
+    // FIXME - figure out how to correctly compute display_id
+    this.display_id = 0;
+    this.buttons_state = sc.buttons_state;
+    if (e)
+    {
+        this.x = e.offsetX;
+        this.y = e.offsetY;
+
+        sc.mousex = e.offsetX;
+        sc.mousey = e.offsetY;
+    }
+    else
+    {
+        this.x = this.y = this.buttons_state = 0;
+    }
+}
+
+SpiceMsgcMousePosition.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.x, true); at += 4;
+        dv.setUint32(at, this.y, true); at += 4;
+        dv.setUint16(at, this.buttons_state, true); at += 2;
+        dv.setUint8(at, this.display_id, true); at += 1;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 11;
+    }
+}
+
+function SpiceMsgcMouseMotion(sc, e)
+{
+    // FIXME - figure out how to correctly compute display_id
+    this.display_id = 0;
+    this.buttons_state = sc.buttons_state;
+    if (e)
+    {
+        this.x = e.offsetX;
+        this.y = e.offsetY;
+
+        if (sc.mousex !== undefined)
+        {
+            this.x -= sc.mousex;
+            this.y -= sc.mousey;
+        }
+        sc.mousex = e.offsetX;
+        sc.mousey = e.offsetY;
+    }
+    else
+    {
+        this.x = this.y = this.buttons_state = 0;
+    }
+}
+
+/* Use the same functions as for MousePosition */
+SpiceMsgcMouseMotion.prototype.to_buffer = SpiceMsgcMousePosition.prototype.to_buffer;
+SpiceMsgcMouseMotion.prototype.buffer_size = SpiceMsgcMousePosition.prototype.buffer_size;
+
+function SpiceMsgcMousePress(sc, e)
+{
+    if (e)
+    {
+        this.button = e.button + 1;
+        this.buttons_state = 1 << e.button;
+        sc.buttons_state = this.buttons_state;
+    }
+    else
+    {
+        this.button = Constants.SPICE_MOUSE_BUTTON_LEFT;
+        this.buttons_state = Constants.SPICE_MOUSE_BUTTON_MASK_LEFT;
+    }
+}
+
+SpiceMsgcMousePress.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint8(at, this.button, true); at ++;
+        dv.setUint16(at, this.buttons_state, true); at += 2;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 3;
+    }
+}
+
+function SpiceMsgcMouseRelease(sc, e)
+{
+    if (e)
+    {
+        this.button = e.button + 1;
+        this.buttons_state = 0;
+        sc.buttons_state = this.buttons_state;
+    }
+    else
+    {
+        this.button = Constants.SPICE_MOUSE_BUTTON_LEFT;
+        this.buttons_state = 0;
+    }
+}
+
+/* Use the same functions as for MousePress */
+SpiceMsgcMouseRelease.prototype.to_buffer = SpiceMsgcMousePress.prototype.to_buffer;
+SpiceMsgcMouseRelease.prototype.buffer_size = SpiceMsgcMousePress.prototype.buffer_size;
+
+
+function SpiceMsgcKeyDown(e)
+{
+    if (e)
+    {
+        this.code = keycode_to_start_scan(e.keyCode);
+    }
+    else
+    {
+        this.code = 0;
+    }
+}
+
+SpiceMsgcKeyDown.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.code, true); at += 4;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 4;
+    }
+}
+
+function SpiceMsgcKeyUp(e)
+{
+    if (e)
+    {
+        this.code = keycode_to_end_scan(e.keyCode);
+    }
+    else
+    {
+        this.code = 0;
+    }
+}
+
+/* Use the same functions as for KeyDown */
+SpiceMsgcKeyUp.prototype.to_buffer = SpiceMsgcKeyDown.prototype.to_buffer;
+SpiceMsgcKeyUp.prototype.buffer_size = SpiceMsgcKeyDown.prototype.buffer_size;
+
+function SpiceMsgDisplayStreamCreate(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayStreamCreate.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.surface_id = dv.getUint32(at, true); at += 4;
+        this.id = dv.getUint32(at, true); at += 4;
+        this.flags = dv.getUint8(at, true); at += 1;
+        this.codec_type = dv.getUint8(at, true); at += 1;
+        this.stamp = dv.getUint64(at, true); at += 8;
+        this.stream_width = dv.getUint32(at, true); at += 4;
+        this.stream_height = dv.getUint32(at, true); at += 4;
+        this.src_width = dv.getUint32(at, true); at += 4;
+        this.src_height = dv.getUint32(at, true); at += 4;
+
+        this.dest = new SpiceRect;
+        at = this.dest.from_dv(dv, at, a);
+        this.clip = new SpiceClip;
+        this.clip.from_dv(dv, at, a);
+    },
+}
+
+function SpiceStreamDataHeader(a, at)
+{
+}
+
+SpiceStreamDataHeader.prototype =
+{
+    from_dv : function(dv, at, mb)
+    {
+        this.id = dv.getUint32(at, true); at += 4;
+        this.multi_media_time = dv.getUint32(at, true); at += 4;
+        return at;
+    },
+}
+
+function SpiceMsgDisplayStreamData(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayStreamData.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.base = new SpiceStreamDataHeader;
+        at = this.base.from_dv(dv, at, a);
+        this.data_size = dv.getUint32(at, true); at += 4;
+        this.data = dv.u8.subarray(at, at + this.data_size);
+    },
+}
+
+function SpiceMsgDisplayStreamDataSized(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayStreamDataSized.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.base = new SpiceStreamDataHeader;
+        at = this.base.from_dv(dv, at, a);
+        this.width = dv.getUint32(at, true); at += 4;
+        this.height = dv.getUint32(at, true); at += 4;
+        this.dest = new SpiceRect;
+        at = this.dest.from_dv(dv, at, a);
+        this.data_size = dv.getUint32(at, true); at += 4;
+        this.data = dv.u8.subarray(at, at + this.data_size);
+    },
+}
+
+
+function SpiceMsgDisplayStreamClip(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayStreamClip.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.id = dv.getUint32(at, true); at += 4;
+        this.clip = new SpiceClip;
+        this.clip.from_dv(dv, at, a);
+    },
+}
+
+function SpiceMsgDisplayStreamDestroy(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayStreamDestroy.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.id = dv.getUint32(at, true); at += 4;
+    },
+}
+
+function SpiceMsgDisplayStreamActivateReport(a, at)
+{
+    this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayStreamActivateReport.prototype =
+{
+    from_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.stream_id = dv.getUint32(at, true); at += 4;
+        this.unique_id = dv.getUint32(at, true); at += 4;
+        this.max_window_size = dv.getUint32(at, true); at += 4;
+        this.timeout_ms = dv.getUint32(at, true); at += 4;
+    },
+}
+
+function SpiceMsgcDisplayStreamReport(stream_id, unique_id)
+{
+    this.stream_id = stream_id;
+    this.unique_id = unique_id;
+    this.start_frame_mm_time = 0;
+    this.end_frame_mm_time = 0;
+    this.num_frames = 0;
+    this.num_drops = 0;
+    this.last_frame_delay = 0;
+
+    // TODO - Implement audio delay
+    this.audio_delay = -1;
+}
+
+SpiceMsgcDisplayStreamReport.prototype =
+{
+    to_buffer: function(a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        dv.setUint32(at, this.stream_id, true); at += 4;
+        dv.setUint32(at, this.unique_id, true); at += 4;
+        dv.setUint32(at, this.start_frame_mm_time, true); at += 4;
+        dv.setUint32(at, this.end_frame_mm_time, true); at += 4;
+        dv.setUint32(at, this.num_frames, true); at += 4;
+        dv.setUint32(at, this.num_drops, true); at += 4;
+        dv.setUint32(at, this.last_frame_delay, true); at += 4;
+        dv.setUint32(at, this.audio_delay, true); at += 4;
+        return at;
+    },
+    buffer_size: function()
+    {
+        return 8 * 4;
+    }
+}
+
+function SpiceMsgDisplayInvalList(a, at)
+{
+    this.count = 0;
+    this.resources = [];
+    this.from_buffer(a,at);
+}
+
+SpiceMsgDisplayInvalList.prototype =
+{
+    from_buffer: function (a, at)
+    {
+        var i;
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        this.count = dv.getUint16(at, true); at += 2;
+        for (i = 0; i < this.count; i++)
+        {
+            this.resources[i] = {};
+            this.resources[i].type = dv.getUint8(at, true); at++;
+            this.resources[i].id = dv.getUint64(at, true); at += 8;
+        }
+    },
+}
+
+function SpiceMsgPortInit(a, at)
+{
+    this.from_buffer(a,at);
+};
+
+SpiceMsgPortInit.prototype =
+{
+    from_buffer: function (a, at)
+    {
+        at = at || 0;
+        var dv = new SpiceDataView(a);
+        var namesize = dv.getUint32(at, true); at += 4;
+        var offset = dv.getUint32(at, true); at += 4;
+        this.opened = dv.getUint8(at, true); at += 1;
+        this.name = a.slice(offset, offset + namesize - 1);
+    }
+}
+
+export {
+  SpiceLinkHeader,
+  SpiceLinkMess,
+  SpiceLinkReply,
+  SpiceLinkAuthTicket,
+  SpiceLinkAuthReply,
+  SpiceMiniData,
+  SpiceMsgChannels,
+  SpiceMsgMainInit,
+  SpiceMsgMainMouseMode,
+  SpiceMsgMainAgentData,
+  SpiceMsgMainAgentTokens,
+  SpiceMsgSetAck,
+  SpiceMsgcAckSync,
+  SpiceMsgcMainMouseModeRequest,
+  SpiceMsgcMainAgentStart,
+  SpiceMsgcMainAgentData,
+  VDAgentAnnounceCapabilities,
+  VDAgentMonitorsConfig,
+  VDAgentFileXferStatusMessage,
+  VDAgentFileXferStartMessage,
+  VDAgentFileXferDataMessage,
+  SpiceMsgNotify,
+  SpiceMsgcDisplayInit,
+  SpiceMsgDisplayBase,
+  SpiceMsgDisplayDrawCopy,
+  SpiceMsgDisplayDrawFill,
+  SpiceMsgDisplayCopyBits,
+  SpiceMsgSurfaceCreate,
+  SpiceMsgSurfaceDestroy,
+  SpiceMsgInputsInit,
+  SpiceMsgInputsKeyModifiers,
+  SpiceMsgCursorInit,
+  SpiceMsgPlaybackData,
+  SpiceMsgPlaybackMode,
+  SpiceMsgPlaybackStart,
+  SpiceMsgCursorSet,
+  SpiceMsgcMousePosition,
+  SpiceMsgcMouseMotion,
+  SpiceMsgcMousePress,
+  SpiceMsgcMouseRelease,
+  SpiceMsgcKeyDown,
+  SpiceMsgcKeyUp,
+  SpiceMsgDisplayStreamCreate,
+  SpiceStreamDataHeader,
+  SpiceMsgDisplayStreamData,
+  SpiceMsgDisplayStreamDataSized,
+  SpiceMsgDisplayStreamClip,
+  SpiceMsgDisplayStreamDestroy,
+  SpiceMsgDisplayStreamActivateReport,
+  SpiceMsgcDisplayStreamReport,
+  SpiceMsgDisplayInvalList,
+  SpiceMsgPortInit,
+};
diff -pruN 0.1.7-5/src/spicetype.js 0.2.2-0ubuntu3/src/spicetype.js
--- 0.1.7-5/src/spicetype.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/spicetype.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,497 @@
+"use strict";
+/*
+   Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
+
+   This file is part of spice-html5.
+
+   spice-html5 is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   spice-html5 is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with spice-html5.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*----------------------------------------------------------------------------
+**  Spice types
+**      This file contains classes for common spice types.
+**  Generally, they are used as helpers in reading and writing messages
+**  to and from the server.
+**--------------------------------------------------------------------------*/
+
+import { Constants } from './enums.js';
+import { SpiceQuic } from './quic.js';
+
+function SpiceChannelId()
+{
+}
+SpiceChannelId.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.type = dv.getUint8(at, true); at ++;
+        this.id = dv.getUint8(at, true); at ++;
+        return at;
+    },
+}
+
+function SpiceRect()
+{
+}
+
+SpiceRect.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.top = dv.getUint32(at, true); at += 4;
+        this.left = dv.getUint32(at, true); at += 4;
+        this.bottom = dv.getUint32(at, true); at += 4;
+        this.right = dv.getUint32(at, true); at += 4;
+        return at;
+    },
+    is_same_size : function(r)
+    {
+        if ((this.bottom - this.top) == (r.bottom - r.top) &&
+            (this.right - this.left) == (r.right - r.left) )
+            return true;
+
+        return false;
+    },
+}
+
+function SpiceClipRects()
+{
+}
+
+SpiceClipRects.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        var i;
+        this.num_rects = dv.getUint32(at, true); at += 4;
+        if (this.num_rects > 0)
+            this.rects = [];
+        for (i = 0; i < this.num_rects; i++)
+        {
+            this.rects[i] = new SpiceRect();
+            at = this.rects[i].from_dv(dv, at, mb);
+        }
+        return at;
+    },
+}
+
+function SpiceClip()
+{
+}
+
+SpiceClip.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.type = dv.getUint8(at, true); at ++;
+        if (this.type == Constants.SPICE_CLIP_TYPE_RECTS)
+        {
+            this.rects = new SpiceClipRects();
+            at = this.rects.from_dv(dv, at, mb);
+        }
+        return at;
+    },
+}
+
+function SpiceImageDescriptor()
+{
+}
+
+SpiceImageDescriptor.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.id = dv.getUint64(at, true); at += 8;
+        this.type  = dv.getUint8(at, true); at ++;
+        this.flags = dv.getUint8(at, true); at ++;
+        this.width = dv.getUint32(at, true); at += 4;
+        this.height= dv.getUint32(at, true); at += 4;
+        return at;
+    },
+}
+
+function SpicePalette()
+{
+}
+
+SpicePalette.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        var i;
+        this.unique = dv.getUint64(at, true); at += 8;
+        this.num_ents = dv.getUint16(at, true); at += 2;
+        this.ents = [];
+        for (i = 0; i < this.num_ents; i++)
+        {
+            this.ents[i] = dv.getUint32(at, true); at += 4;
+        }
+        return at;
+    },
+}
+
+function SpiceBitmap()
+{
+}
+
+SpiceBitmap.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.format = dv.getUint8(at, true); at++;
+        this.flags  = dv.getUint8(at, true); at++;
+        this.x = dv.getUint32(at, true); at += 4;
+        this.y = dv.getUint32(at, true); at += 4;
+        this.stride = dv.getUint32(at, true); at += 4;
+        if (this.flags & Constants.SPICE_BITMAP_FLAGS_PAL_FROM_CACHE)
+        {
+            this.palette_id = dv.getUint64(at, true); at += 8;
+        }
+        else
+        {
+            var offset = dv.getUint32(at, true); at += 4;
+            if (offset == 0)
+                this.palette = null;
+            else
+            {
+                this.palette = new SpicePalette;
+                this.palette.from_dv(dv, offset, mb);
+            }
+        }
+        // FIXME - should probably constrain this to the offset
+        //          of palette, if non zero
+        this.data   = mb.slice(at);
+        at += this.data.byteLength;
+        return at;
+    },
+}
+
+function SpiceImage()
+{
+}
+
+SpiceImage.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.descriptor = new SpiceImageDescriptor;
+        at = this.descriptor.from_dv(dv, at, mb);
+
+        if (this.descriptor.type == Constants.SPICE_IMAGE_TYPE_LZ_RGB)
+        {
+            this.lz_rgb = new Object();
+            this.lz_rgb.length = dv.getUint32(at, true); at += 4;
+            var initial_at = at;
+            this.lz_rgb.magic = "";
+            for (var i = 3; i >= 0; i--)
+                this.lz_rgb.magic += String.fromCharCode(dv.getUint8(at + i));
+            at += 4;
+
+            // NOTE:  The endian change is *correct*
+            this.lz_rgb.version = dv.getUint32(at); at += 4;
+            this.lz_rgb.type = dv.getUint32(at); at += 4;
+            this.lz_rgb.width = dv.getUint32(at); at += 4;
+            this.lz_rgb.height = dv.getUint32(at); at += 4;
+            this.lz_rgb.stride = dv.getUint32(at); at += 4;
+            this.lz_rgb.top_down = dv.getUint32(at); at += 4;
+
+            var header_size = at - initial_at;
+
+            this.lz_rgb.data   = mb.slice(at, this.lz_rgb.length + at - header_size);
+            at += this.lz_rgb.data.byteLength;
+
+        }
+
+        if (this.descriptor.type == Constants.SPICE_IMAGE_TYPE_BITMAP)
+        {
+            this.bitmap = new SpiceBitmap;
+            at = this.bitmap.from_dv(dv, at, mb);
+        }
+
+        if (this.descriptor.type == Constants.SPICE_IMAGE_TYPE_SURFACE)
+        {
+            this.surface_id = dv.getUint32(at, true); at += 4;
+        }
+
+        if (this.descriptor.type == Constants.SPICE_IMAGE_TYPE_JPEG)
+        {
+            this.jpeg = new Object;
+            this.jpeg.data_size = dv.getUint32(at, true); at += 4;
+            this.jpeg.data = mb.slice(at);
+            at += this.jpeg.data.byteLength;
+        }
+
+        if (this.descriptor.type == Constants.SPICE_IMAGE_TYPE_JPEG_ALPHA)
+        {
+            this.jpeg_alpha = new Object;
+            this.jpeg_alpha.flags = dv.getUint8(at, true); at += 1;
+            this.jpeg_alpha.jpeg_size = dv.getUint32(at, true); at += 4;
+            this.jpeg_alpha.data_size = dv.getUint32(at, true); at += 4;
+            this.jpeg_alpha.data = mb.slice(at, this.jpeg_alpha.jpeg_size + at);
+            at += this.jpeg_alpha.data.byteLength;
+            // Alpha channel is an LZ image
+            this.jpeg_alpha.alpha = new Object();
+            this.jpeg_alpha.alpha.length = this.jpeg_alpha.data_size - this.jpeg_alpha.jpeg_size;
+            var initial_at = at;
+            this.jpeg_alpha.alpha.magic = "";
+            for (var i = 3; i >= 0; i--)
+                this.jpeg_alpha.alpha.magic += String.fromCharCode(dv.getUint8(at + i));
+            at += 4;
+
+            // NOTE:  The endian change is *correct*
+            this.jpeg_alpha.alpha.version = dv.getUint32(at); at += 4;
+            this.jpeg_alpha.alpha.type = dv.getUint32(at); at += 4;
+            this.jpeg_alpha.alpha.width = dv.getUint32(at); at += 4;
+            this.jpeg_alpha.alpha.height = dv.getUint32(at); at += 4;
+            this.jpeg_alpha.alpha.stride = dv.getUint32(at); at += 4;
+            this.jpeg_alpha.alpha.top_down = dv.getUint32(at); at += 4;
+
+            var header_size = at - initial_at;
+
+            this.jpeg_alpha.alpha.data   = mb.slice(at, this.jpeg_alpha.alpha.length + at - header_size);
+            at += this.jpeg_alpha.alpha.data.byteLength;
+        }
+
+        if (this.descriptor.type == Constants.SPICE_IMAGE_TYPE_QUIC)
+        {
+            this.quic = new SpiceQuic;
+            at = this.quic.from_dv(dv, at, mb);
+        }
+        return at;
+    },
+}
+
+
+function SpiceQMask()
+{
+}
+
+SpiceQMask.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.flags  = dv.getUint8(at, true); at++;
+        this.pos = new SpicePoint;
+        at = this.pos.from_dv(dv, at, mb);
+        var offset = dv.getUint32(at, true); at += 4;
+        if (offset == 0)
+        {
+            this.bitmap = null;
+            return at;
+        }
+
+        this.bitmap = new SpiceImage;
+        return this.bitmap.from_dv(dv, offset, mb);
+    },
+}
+
+
+function SpicePattern()
+{
+}
+
+SpicePattern.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        var offset = dv.getUint32(at, true); at += 4;
+        if (offset == 0)
+        {
+            this.pat = null;
+        }
+        else
+        {
+            this.pat = new SpiceImage;
+            this.pat.from_dv(dv, offset, mb);
+        }
+
+        this.pos = new SpicePoint;
+        return this.pos.from_dv(dv, at, mb);
+    }
+}
+
+function SpiceBrush()
+{
+}
+
+SpiceBrush.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.type = dv.getUint8(at, true); at ++;
+        if (this.type == Constants.SPICE_BRUSH_TYPE_SOLID)
+        {
+            this.color = dv.getUint32(at, true); at += 4;
+        }
+        else if (this.type == Constants.SPICE_BRUSH_TYPE_PATTERN)
+        {
+            this.pattern = new SpicePattern;
+            at = this.pattern.from_dv(dv, at, mb);
+        }
+        return at;
+    },
+}
+
+function SpiceFill()
+{
+}
+
+SpiceFill.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.brush = new SpiceBrush;
+        at = this.brush.from_dv(dv, at, mb);
+        this.rop_descriptor = dv.getUint16(at, true); at += 2;
+        this.mask = new SpiceQMask;
+        return this.mask.from_dv(dv, at, mb);
+    },
+}
+
+
+function SpiceCopy()
+{
+}
+
+SpiceCopy.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        var offset = dv.getUint32(at, true); at += 4;
+        if (offset == 0)
+        {
+            this.src_bitmap = null;
+        }
+        else
+        {
+            this.src_bitmap = new SpiceImage;
+            this.src_bitmap.from_dv(dv, offset, mb);
+        }
+        this.src_area = new SpiceRect;
+        at = this.src_area.from_dv(dv, at, mb);
+        this.rop_descriptor = dv.getUint16(at, true); at += 2;
+        this.scale_mode = dv.getUint8(at, true); at ++;
+        this.mask = new SpiceQMask;
+        return this.mask.from_dv(dv, at, mb);
+    },
+}
+
+function SpicePoint16()
+{
+}
+
+SpicePoint16.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.x = dv.getUint16(at, true); at += 2;
+        this.y = dv.getUint16(at, true); at += 2;
+        return at;
+    },
+}
+
+function SpicePoint()
+{
+}
+
+SpicePoint.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.x = dv.getUint32(at, true); at += 4;
+        this.y = dv.getUint32(at, true); at += 4;
+        return at;
+    },
+}
+
+function SpiceCursorHeader()
+{
+}
+
+SpiceCursorHeader.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.unique = dv.getUint64(at, true); at += 8;
+        this.type = dv.getUint8(at, true); at ++;
+        this.width = dv.getUint16(at, true); at += 2;
+        this.height = dv.getUint16(at, true); at += 2;
+        this.hot_spot_x = dv.getUint16(at, true); at += 2;
+        this.hot_spot_y = dv.getUint16(at, true); at += 2;
+        return at;
+    },
+}
+
+function SpiceCursor()
+{
+}
+
+SpiceCursor.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.flags = dv.getUint16(at, true); at += 2;
+        if (this.flags & Constants.SPICE_CURSOR_FLAGS_NONE)
+            this.header = null;
+        else
+        {
+            this.header = new SpiceCursorHeader;
+            at = this.header.from_dv(dv, at, mb);
+            this.data   = mb.slice(at);
+            at += this.data.byteLength;
+        }
+        return at;
+    },
+}
+
+function SpiceSurface()
+{
+}
+
+SpiceSurface.prototype =
+{
+    from_dv: function(dv, at, mb)
+    {
+        this.surface_id = dv.getUint32(at, true); at += 4;
+        this.width = dv.getUint32(at, true); at += 4;
+        this.height = dv.getUint32(at, true); at += 4;
+        this.format = dv.getUint32(at, true); at += 4;
+        this.flags = dv.getUint32(at, true); at += 4;
+        return at;
+    },
+}
+
+/* FIXME - SpiceImage  types lz_plt, jpeg, zlib_glz, and jpeg_alpha are
+           completely unimplemented */
+
+export {
+  SpiceChannelId,
+  SpiceRect,
+  SpiceClipRects,
+  SpiceClip,
+  SpiceImageDescriptor,
+  SpicePalette,
+  SpiceBitmap,
+  SpiceImage,
+  SpiceQMask,
+  SpicePattern,
+  SpiceBrush,
+  SpiceFill,
+  SpiceCopy,
+  SpicePoint16,
+  SpicePoint,
+  SpiceCursorHeader,
+  SpiceCursor,
+  SpiceSurface,
+};
diff -pruN 0.1.7-5/src/thirdparty/browser-es-module-loader/dist/babel-worker.js 0.2.2-0ubuntu3/src/thirdparty/browser-es-module-loader/dist/babel-worker.js
--- 0.1.7-5/src/thirdparty/browser-es-module-loader/dist/babel-worker.js	1970-01-01 00:00:00.000000000 +0000
+++ 0.2.2-0ubuntu3/src/thirdparty/browser-es-module-loader/dist/babel-worker.js	2019-08-06 11:45:18.000000000 +0000
@@ -0,0 +1,55799 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+'use strict';
+module.exports = function () {
+	return /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g;
+};
+
+},{}],2:[function(require,module,exports){
+'use strict';
+
+function assembleStyles () {
+	var styles = {
+		modifiers: {
+			reset: [0, 0],
+			bold: [1, 22], // 21 isn't widely supported and 22 does the same thing
+			dim: [2, 22],
+			italic: [3, 23],
+			underline: [4, 24],
+			inverse: [7, 27],
+			hidden: [8, 28],
+			strikethrough: [9, 29]
+		},
+		colors: {
+			black: [30, 39],
+			red: [31, 39],
+			green: [32, 39],
+			yellow: [33, 39],
+			blue: [34, 39],
+			magenta: [35, 39],
+			cyan: [36, 39],
+			white: [37, 39],
+			gray: [90, 39]
+		},
+		bgColors: {
+			bgBlack: [40, 49],
+			bgRed: [41, 49],
+			bgGreen: [42, 49],
+			bgYellow: [43, 49],
+			bgBlue: [44, 49],
+			bgMagenta: [45, 49],
+			bgCyan: [46, 49],
+			bgWhite: [47, 49]
+		}
+	};
+
+	// fix humans
+	styles.colors.grey = styles.colors.gray;
+
+	Object.keys(styles).forEach(function (groupName) {
+		var group = styles[groupName];
+
+		Object.keys(group).forEach(function (styleName) {
+			var style = group[styleName];
+
+			styles[styleName] = group[styleName] = {
+				open: '\u001b[' + style[0] + 'm',
+				close: '\u001b[' + style[1] + 'm'
+			};
+		});
+
+		Object.defineProperty(styles, groupName, {
+			value: group,
+			enumerable: false
+		});
+	});
+
+	return styles;
+}
+
+Object.defineProperty(module, 'exports', {
+	enumerable: true,
+	get: assembleStyles
+});
+
+},{}],3:[function(require,module,exports){
+(function (global){
+'use strict';
+
+// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js
+// original notice:
+
+/*!
+ * The buffer module from node.js, for the browser.
+ *
+ * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
+ * @license  MIT
+ */
+function compare(a, b) {
+  if (a === b) {
+    return 0;
+  }
+
+  var x = a.length;
+  var y = b.length;
+
+  for (var i = 0, len = Math.min(x, y); i < len; ++i) {
+    if (a[i] !== b[i]) {
+      x = a[i];
+      y = b[i];
+      break;
+    }
+  }
+
+  if (x < y) {
+    return -1;
+  }
+  if (y < x) {
+    return 1;
+  }
+  return 0;
+}
+function isBuffer(b) {
+  if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {
+    return global.Buffer.isBuffer(b);
+  }
+  return !!(b != null && b._isBuffer);
+}
+
+// based on node assert, original notice:
+
+// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
+//
+// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
+//
+// Originally from narwhal.js (http://narwhaljs.org)
+// Copyright (c) 2009 Thomas Robinson <280north.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the 'Software'), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var util = require('util/');
+var hasOwn = Object.prototype.hasOwnProperty;
+var pSlice = Array.prototype.slice;
+var functionsHaveNames = (function () {
+  return function foo() {}.name === 'foo';
+}());
+function pToString (obj) {
+  return Object.prototype.toString.call(obj);
+}
+function isView(arrbuf) {
+  if (isBuffer(arrbuf)) {
+    return false;
+  }
+  if (typeof global.ArrayBuffer !== 'function') {
+    return false;
+  }
+  if (typeof ArrayBuffer.isView === 'function') {
+    return ArrayBuffer.isView(arrbuf);
+  }
+  if (!arrbuf) {
+    return false;
+  }
+  if (arrbuf instanceof DataView) {
+    return true;
+  }
+  if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {
+    return true;
+  }
+  return false;
+}
+// 1. The assert module provides functions that throw
+// AssertionError's when particular conditions are not met. The
+// assert module must conform to the following interface.
+
+var assert = module.exports = ok;
+
+// 2. The AssertionError is defined in assert.
+// new assert.AssertionError({ message: message,
+//                             actual: actual,
+//                             expected: expected })
+
+var regex = /\s*function\s+([^\(\s]*)\s*/;
+// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js
+function getName(func) {
+  if (!util.isFunction(func)) {
+    return;
+  }
+  if (functionsHaveNames) {
+    return func.name;
+  }
+  var str = func.toString();
+  var match = str.match(regex);
+  return match && match[1];
+}
+assert.AssertionError = function AssertionError(options) {
+  this.name = 'AssertionError';
+  this.actual = options.actual;
+  this.expected = options.expected;
+  this.operator = options.operator;
+  if (options.message) {
+    this.message = options.message;
+    this.generatedMessage = false;
+  } else {
+    this.message = getMessage(this);
+    this.generatedMessage = true;
+  }
+  var stackStartFunction = options.stackStartFunction || fail;
+  if (Error.captureStackTrace) {
+    Error.captureStackTrace(this, stackStartFunction);
+  } else {
+    // non v8 browsers so we can have a stacktrace
+    var err = new Error();
+    if (err.stack) {
+      var out = err.stack;
+
+      // try to strip useless frames
+      var fn_name = getName(stackStartFunction);
+      var idx = out.indexOf('\n' + fn_name);
+      if (idx >= 0) {
+        // once we have located the function frame
+        // we need to strip out everything before it (and its line)
+        var next_line = out.indexOf('\n', idx + 1);
+        out = out.substring(next_line + 1);
+      }
+
+      this.stack = out;
+    }
+  }
+};
+
+// assert.AssertionError instanceof Error
+util.inherits(assert.AssertionError, Error);
+
+function truncate(s, n) {
+  if (typeof s === 'string') {
+    return s.length < n ? s : s.slice(0, n);
+  } else {
+    return s;
+  }
+}
+function inspect(something) {
+  if (functionsHaveNames || !util.isFunction(something)) {
+    return util.inspect(something);
+  }
+  var rawname = getName(something);
+  var name = rawname ? ': ' + rawname : '';
+  return '[Function' +  name + ']';
+}
+function getMessage(self) {
+  return truncate(inspect(self.actual), 128) + ' ' +
+         self.operator + ' ' +
+         truncate(inspect(self.expected), 128);
+}
+
+// At present only the three keys mentioned above are used and
+// understood by the spec. Implementations or sub modules can pass
+// other keys to the AssertionError's constructor - they will be
+// ignored.
+
+// 3. All of the following functions must throw an AssertionError
+// when a corresponding condition is not met, with a message that
+// may be undefined if not provided.  All assertion methods provide
+// both the actual and expected values to the assertion error for
+// display purposes.
+
+function fail(actual, expected, message, operator, stackStartFunction) {
+  throw new assert.AssertionError({
+    message: message,
+    actual: actual,
+    expected: expected,
+    operator: operator,
+    stackStartFunction: stackStartFunction
+  });
+}
+
+// EXTENSION! allows for well behaved errors defined elsewhere.
+assert.fail = fail;
+
+// 4. Pure assertion tests whether a value is truthy, as determined
+// by !!guard.
+// assert.ok(guard, message_opt);
+// This statement is equivalent to assert.equal(true, !!guard,
+// message_opt);. To test strictly for the value true, use
+// assert.strictEqual(true, guard, message_opt);.
+
+function ok(value, message) {
+  if (!value) fail(value, true, message, '==', assert.ok);
+}
+assert.ok = ok;
+
+// 5. The equality assertion tests shallow, coercive equality with
+// ==.
+// assert.equal(actual, expected, message_opt);
+
+assert.equal = function equal(actual, expected, message) {
+  if (actual != expected) fail(actual, expected, message, '==', assert.equal);
+};
+
+// 6. The non-equality assertion tests for whether two objects are not equal
+// with != assert.notEqual(actual, expected, message_opt);
+
+assert.notEqual = function notEqual(actual, expected, message) {
+  if (actual == expected) {
+    fail(actual, expected, message, '!=', assert.notEqual);
+  }
+};
+
+// 7. The equivalence assertion tests a deep equality relation.
+// assert.deepEqual(actual, expected, message_opt);
+
+assert.deepEqual = function deepEqual(actual, expected, message) {
+  if (!_deepEqual(actual, expected, false)) {
+    fail(actual, expected, message, 'deepEqual', assert.deepEqual);
+  }
+};
+
+assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
+  if (!_deepEqual(actual, expected, true)) {
+    fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
+  }
+};
+
+function _deepEqual(actual, expected, strict, memos) {
+  // 7.1. All identical values are equivalent, as determined by ===.
+  if (actual === expected) {
+    return true;
+  } else if (isBuffer(actual) && isBuffer(expected)) {
+    return compare(actual, expected) === 0;
+
+  // 7.2. If the expected value is a Date object, the actual value is
+  // equivalent if it is also a Date object that refers to the same time.
+  } else if (util.isDate(actual) && util.isDate(expected)) {
+    return actual.getTime() === expected.getTime();
+
+  // 7.3 If the expected value is a RegExp object, the actual value is
+  // equivalent if it is also a RegExp object with the same source and
+  // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
+  } else if (util.isRegExp(actual) && util.isRegExp(expected)) {
+    return actual.source === expected.source &&
+           actual.global === expected.global &&
+           actual.multiline === expected.multiline &&
+           actual.lastIndex === expected.lastIndex &&
+           actual.ignoreCase === expected.ignoreCase;
+
+  // 7.4. Other pairs that do not both pass typeof value == 'object',
+  // equivalence is determined by ==.
+  } else if ((actual === null || typeof actual !== 'object') &&
+             (expected === null || typeof expected !== 'object')) {
+    return strict ? actual === expected : actual == expected;
+
+  // If both values are instances of typed arrays, wrap their underlying
+  // ArrayBuffers in a Buffer each to increase performance
+  // This optimization requires the arrays to have the same type as checked by
+  // Object.prototype.toString (aka pToString). Never perform binary
+  // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their
+  // bit patterns are not identical.
+  } else if (isView(actual) && isView(expected) &&
+             pToString(actual) === pToString(expected) &&
+             !(actual instanceof Float32Array ||
+               actual instanceof Float64Array)) {
+    return compare(new Uint8Array(actual.buffer),
+                   new Uint8Array(expected.buffer)) === 0;
+
+  // 7.5 For all other Object pairs, including Array objects, equivalence is
+  // determined by having the same number of owned properties (as verified
+  // with Object.prototype.hasOwnProperty.call), the same set of keys
+  // (although not necessarily the same order), equivalent values for every
+  // corresponding key, and an identical 'prototype' property. Note: this
+  // accounts for both named and indexed properties on Arrays.
+  } else if (isBuffer(actual) !== isBuffer(expected)) {
+    return false;
+  } else {
+    memos = memos || {actual: [], expected: []};
+
+    var actualIndex = memos.actual.indexOf(actual);
+    if (actualIndex !== -1) {
+      if (actualIndex === memos.expected.indexOf(expected)) {
+        return true;
+      }
+    }
+
+    memos.actual.push(actual);
+    memos.expected.push(expected);
+
+    return objEquiv(actual, expected, strict, memos);
+  }
+}
+
+function isArguments(object) {
+  return Object.prototype.toString.call(object) == '[object Arguments]';
+}
+
+function objEquiv(a, b, strict, actualVisitedObjects) {
+  if (a === null || a === undefined || b === null || b === undefined)
+    return false;
+  // if one is a primitive, the other must be same
+  if (util.isPrimitive(a) || util.isPrimitive(b))
+    return a === b;
+  if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
+    return false;
+  var aIsArgs = isArguments(a);
+  var bIsArgs = isArguments(b);
+  if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
+    return false;
+  if (aIsArgs) {
+    a = pSlice.call(a);
+    b = pSlice.call(b);
+    return _deepEqual(a, b, strict);
+  }
+  var ka = objectKeys(a);
+  var kb = objectKeys(b);
+  var key, i;
+  // having the same number of owned properties (keys incorporates
+  // hasOwnProperty)
+  if (ka.length !== kb.length)
+    return false;
+  //the same set of keys (although not necessarily the same order),
+  ka.sort();
+  kb.sort();
+  //~~~cheap key test
+  for (i = ka.length - 1; i >= 0; i--) {
+    if (ka[i] !== kb[i])
+      return false;
+  }
+  //equivalent values for every corresponding key, and
+  //~~~possibly expensive deep test
+  for (i = ka.length - 1; i >= 0; i--) {
+    key = ka[i];
+    if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
+      return false;
+  }
+  return true;
+}
+
+// 8. The non-equivalence assertion tests for any deep inequality.
+// assert.notDeepEqual(actual, expected, message_opt);
+
+assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
+  if (_deepEqual(actual, expected, false)) {
+    fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
+  }
+};
+
+assert.notDeepStrictEqual = notDeepStrictEqual;
+function notDeepStrictEqual(actual, expected, message) {
+  if (_deepEqual(actual, expected, true)) {
+    fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
+  }
+}
+
+
+// 9. The strict equality assertion tests strict equality, as determined by ===.
+// assert.strictEqual(actual, expected, message_opt);
+
+assert.strictEqual = function strictEqual(actual, expected, message) {
+  if (actual !== expected) {
+    fail(actual, expected, message, '===', assert.strictEqual);
+  }
+};
+
+// 10. The strict non-equality assertion tests for strict inequality, as
+// determined by !==.  assert.notStrictEqual(actual, expected, message_opt);
+
+assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
+  if (actual === expected) {
+    fail(actual, expected, message, '!==', assert.notStrictEqual);
+  }
+};
+
+function expectedException(actual, expected) {
+  if (!actual || !expected) {
+    return false;
+  }
+
+  if (Object.prototype.toString.call(expected) == '[object RegExp]') {
+    return expected.test(actual);
+  }
+
+  try {
+    if (actual instanceof expected) {
+      return true;
+    }
+  } catch (e) {
+    // Ignore.  The instanceof check doesn't work for arrow functions.
+  }
+
+  if (Error.isPrototypeOf(expected)) {
+    return false;
+  }
+
+  return expected.call({}, actual) === true;
+}
+
+function _tryBlock(block) {
+  var error;
+  try {
+    block();
+  } catch (e) {
+    error = e;
+  }
+  return error;
+}
+
+function _throws(shouldThrow, block, expected, message) {
+  var actual;
+
+  if (typeof block !== 'function') {
+    throw new TypeError('"block" argument must be a function');
+  }
+
+  if (typeof expected === 'string') {
+    message = expected;
+    expected = null;
+  }
+
+  actual = _tryBlock(block);
+
+  message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
+            (message ? ' ' + message : '.');
+
+  if (shouldThrow && !actual) {
+    fail(actual, expected, 'Missing expected exception' + message);
+  }
+
+  var userProvidedMessage = typeof message === 'string';
+  var isUnwantedException = !shouldThrow && util.isError(actual);
+  var isUnexpectedException = !shouldThrow && actual && !expected;
+
+  if ((isUnwantedException &&
+      userProvidedMessage &&
+      expectedException(actual, expected)) ||
+      isUnexpectedException) {
+    fail(actual, expected, 'Got unwanted exception' + message);
+  }
+
+  if ((shouldThrow && actual && expected &&
+      !expectedException(actual, expected)) || (!shouldThrow && actual)) {
+    throw actual;
+  }
+}
+
+// 11. Expected to throw an error:
+// assert.throws(block, Error_opt, message_opt);
+
+assert.throws = function(block, /*optional*/error, /*optional*/message) {
+  _throws(true, block, error, message);
+};
+
+// EXTENSION! This is annoying to write outside this module.
+assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
+  _throws(false, block, error, message);
+};
+
+assert.ifError = function(err) { if (err) throw err; };
+
+var objectKeys = Object.keys || function (obj) {
+  var keys = [];
+  for (var key in obj) {
+    if (hasOwn.call(obj, key)) keys.push(key);
+  }
+  return keys;
+};
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"util/":560}],4:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (rawLines, lineNumber, colNumber) {
+  var opts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+
+  colNumber = Math.max(colNumber, 0);
+
+  var highlighted = opts.highlightCode && _chalk2.default.supportsColor || opts.forceColor;
+  var chalk = _chalk2.default;
+  if (opts.forceColor) {
+    chalk = new _chalk2.default.constructor({ enabled: true });
+  }
+  var maybeHighlight = function maybeHighlight(chalkFn, string) {
+    return highlighted ? chalkFn(string) : string;
+  };
+  var defs = getDefs(chalk);
+  if (highlighted) rawLines = highlight(defs, rawLines);
+
+  var linesAbove = opts.linesAbove || 2;
+  var linesBelow = opts.linesBelow || 3;
+
+  var lines = rawLines.split(NEWLINE);
+  var start = Math.max(lineNumber - (linesAbove + 1), 0);
+  var end = Math.min(lines.length, lineNumber + linesBelow);
+
+  if (!lineNumber && !colNumber) {
+    start = 0;
+    end = lines.length;
+  }
+
+  var numberMaxWidth = String(end).length;
+
+  var frame = lines.slice(start, end).map(function (line, index) {
+    var number = start + 1 + index;
+    var paddedNumber = (" " + number).slice(-numberMaxWidth);
+    var gutter = " " + paddedNumber + " | ";
+    if (number === lineNumber) {
+      var markerLine = "";
+      if (colNumber) {
+        var markerSpacing = line.slice(0, colNumber - 1).replace(/[^\t]/g, " ");
+        markerLine = ["\n ", maybeHighlight(defs.gutter, gutter.replace(/\d/g, " ")), markerSpacing, maybeHighlight(defs.marker, "^")].join("");
+      }
+      return [maybeHighlight(defs.marker, ">"), maybeHighlight(defs.gutter, gutter), line, markerLine].join("");
+    } else {
+      return " " + maybeHighlight(defs.gutter, gutter) + line;
+    }
+  }).join("\n");
+
+  if (highlighted) {
+    return chalk.reset(frame);
+  } else {
+    return frame;
+  }
+};
+
+var _jsTokens = require("js-tokens");
+
+var _jsTokens2 = _interopRequireDefault(_jsTokens);
+
+var _esutils = require("esutils");
+
+var _esutils2 = _interopRequireDefault(_esutils);
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function getDefs(chalk) {
+  return {
+    keyword: chalk.cyan,
+    capitalized: chalk.yellow,
+    jsx_tag: chalk.yellow,
+    punctuator: chalk.yellow,
+
+    number: chalk.magenta,
+    string: chalk.green,
+    regex: chalk.magenta,
+    comment: chalk.grey,
+    invalid: chalk.white.bgRed.bold,
+    gutter: chalk.grey,
+    marker: chalk.red.bold
+  };
+}
+
+var NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
+
+var JSX_TAG = /^[a-z][\w-]*$/i;
+
+var BRACKET = /^[()\[\]{}]$/;
+
+function getTokenType(match) {
+  var _match$slice = match.slice(-2),
+      offset = _match$slice[0],
+      text = _match$slice[1];
+
+  var token = (0, _jsTokens.matchToToken)(match);
+
+  if (token.type === "name") {
+    if (_esutils2.default.keyword.isReservedWordES6(token.value)) {
+      return "keyword";
+    }
+
+    if (JSX_TAG.test(token.value) && (text[offset - 1] === "<" || text.substr(offset - 2, 2) == "</")) {
+      return "jsx_tag";
+    }
+
+    if (token.value[0] !== token.value[0].toLowerCase()) {
+      return "capitalized";
+    }
+  }
+
+  if (token.type === "punctuator" && BRACKET.test(token.value)) {
+    return "bracket";
+  }
+
+  return token.type;
+}
+
+function highlight(defs, text) {
+  return text.replace(_jsTokens2.default, function () {
+    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
+    }
+
+    var type = getTokenType(args);
+    var colorize = defs[type];
+    if (colorize) {
+      return args[0].split(NEWLINE).map(function (str) {
+        return colorize(str);
+      }).join("\n");
+    } else {
+      return args[0];
+    }
+  });
+}
+
+module.exports = exports["default"];
+},{"chalk":161,"esutils":287,"js-tokens":295}],5:[function(require,module,exports){
+module.exports = require("./lib/api/node.js");
+
+},{"./lib/api/node.js":6}],6:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.transformFromAst = exports.transform = exports.analyse = exports.Pipeline = exports.OptionManager = exports.traverse = exports.types = exports.messages = exports.util = exports.version = exports.resolvePreset = exports.resolvePlugin = exports.template = exports.buildExternalHelpers = exports.options = exports.File = undefined;
+
+var _file = require("../transformation/file");
+
+Object.defineProperty(exports, "File", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_file).default;
+  }
+});
+
+var _config = require("../transformation/file/options/config");
+
+Object.defineProperty(exports, "options", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_config).default;
+  }
+});
+
+var _buildExternalHelpers = require("../tools/build-external-helpers");
+
+Object.defineProperty(exports, "buildExternalHelpers", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_buildExternalHelpers).default;
+  }
+});
+
+var _babelTemplate = require("babel-template");
+
+Object.defineProperty(exports, "template", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_babelTemplate).default;
+  }
+});
+
+var _resolvePlugin = require("../helpers/resolve-plugin");
+
+Object.defineProperty(exports, "resolvePlugin", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_resolvePlugin).default;
+  }
+});
+
+var _resolvePreset = require("../helpers/resolve-preset");
+
+Object.defineProperty(exports, "resolvePreset", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_resolvePreset).default;
+  }
+});
+
+var _package = require("../../package");
+
+Object.defineProperty(exports, "version", {
+  enumerable: true,
+  get: function get() {
+    return _package.version;
+  }
+});
+exports.Plugin = Plugin;
+exports.transformFile = transformFile;
+exports.transformFileSync = transformFileSync;
+
+var _fs = require("fs");
+
+var _fs2 = _interopRequireDefault(_fs);
+
+var _util = require("../util");
+
+var util = _interopRequireWildcard(_util);
+
+var _babelMessages = require("babel-messages");
+
+var messages = _interopRequireWildcard(_babelMessages);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+var _babelTraverse = require("babel-traverse");
+
+var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
+
+var _optionManager = require("../transformation/file/options/option-manager");
+
+var _optionManager2 = _interopRequireDefault(_optionManager);
+
+var _pipeline = require("../transformation/pipeline");
+
+var _pipeline2 = _interopRequireDefault(_pipeline);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.util = util;
+exports.messages = messages;
+exports.types = t;
+exports.traverse = _babelTraverse2.default;
+exports.OptionManager = _optionManager2.default;
+function Plugin(alias) {
+  throw new Error("The (" + alias + ") Babel 5 plugin is being run with Babel 6.");
+}
+
+exports.Pipeline = _pipeline2.default;
+
+
+var pipeline = new _pipeline2.default();
+var analyse = exports.analyse = pipeline.analyse.bind(pipeline);
+var transform = exports.transform = pipeline.transform.bind(pipeline);
+var transformFromAst = exports.transformFromAst = pipeline.transformFromAst.bind(pipeline);
+
+function transformFile(filename, opts, callback) {
+  if (typeof opts === "function") {
+    callback = opts;
+    opts = {};
+  }
+
+  opts.filename = filename;
+
+  _fs2.default.readFile(filename, function (err, code) {
+    var result = void 0;
+
+    if (!err) {
+      try {
+        result = transform(code, opts);
+      } catch (_err) {
+        err = _err;
+      }
+    }
+
+    if (err) {
+      callback(err);
+    } else {
+      callback(null, result);
+    }
+  });
+}
+
+function transformFileSync(filename) {
+  var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+  opts.filename = filename;
+  return transform(_fs2.default.readFileSync(filename, "utf8"), opts);
+}
+},{"../../package":32,"../helpers/resolve-plugin":12,"../helpers/resolve-preset":13,"../tools/build-external-helpers":16,"../transformation/file":17,"../transformation/file/options/config":21,"../transformation/file/options/option-manager":23,"../transformation/pipeline":28,"../util":31,"babel-messages":61,"babel-template":114,"babel-traverse":118,"babel-types":151,"fs":159}],7:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.default = getPossiblePluginNames;
+function getPossiblePluginNames(pluginName) {
+  return ["babel-plugin-" + pluginName, pluginName];
+}
+module.exports = exports["default"];
+},{}],8:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.default = getPossiblePresetNames;
+function getPossiblePresetNames(presetName) {
+  var possibleNames = ["babel-preset-" + presetName, presetName];
+
+  var matches = presetName.match(/^(@[^/]+)\/(.+)$/);
+  if (matches) {
+    var orgName = matches[1],
+        presetPath = matches[2];
+
+    possibleNames.push(orgName + "/babel-preset-" + presetPath);
+  }
+
+  return possibleNames;
+}
+module.exports = exports["default"];
+},{}],9:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (dest, src) {
+  if (!dest || !src) return;
+
+  return (0, _mergeWith2.default)(dest, src, function (a, b) {
+    if (b && Array.isArray(a)) {
+      var newArray = b.slice(0);
+
+      for (var _iterator = a, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+        var _ref;
+
+        if (_isArray) {
+          if (_i >= _iterator.length) break;
+          _ref = _iterator[_i++];
+        } else {
+          _i = _iterator.next();
+          if (_i.done) break;
+          _ref = _i.value;
+        }
+
+        var item = _ref;
+
+        if (newArray.indexOf(item) < 0) {
+          newArray.push(item);
+        }
+      }
+
+      return newArray;
+    }
+  });
+};
+
+var _mergeWith = require("lodash/mergeWith");
+
+var _mergeWith2 = _interopRequireDefault(_mergeWith);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95,"lodash/mergeWith":502}],10:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (ast, comments, tokens) {
+  if (ast) {
+    if (ast.type === "Program") {
+      return t.file(ast, comments || [], tokens || []);
+    } else if (ast.type === "File") {
+      return ast;
+    }
+  }
+
+  throw new Error("Not a valid ast?");
+};
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+module.exports = exports["default"];
+},{"babel-types":151}],11:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.default = resolveFromPossibleNames;
+
+var _resolve = require("./resolve");
+
+var _resolve2 = _interopRequireDefault(_resolve);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function resolveFromPossibleNames(possibleNames, dirname) {
+  return possibleNames.reduce(function (accum, curr) {
+    return accum || (0, _resolve2.default)(curr, dirname);
+  }, null);
+}
+module.exports = exports["default"];
+},{"./resolve":14}],12:[function(require,module,exports){
+(function (process){
+"use strict";
+
+exports.__esModule = true;
+exports.default = resolvePlugin;
+
+var _resolveFromPossibleNames = require("./resolve-from-possible-names");
+
+var _resolveFromPossibleNames2 = _interopRequireDefault(_resolveFromPossibleNames);
+
+var _getPossiblePluginNames = require("./get-possible-plugin-names");
+
+var _getPossiblePluginNames2 = _interopRequireDefault(_getPossiblePluginNames);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function resolvePlugin(pluginName) {
+  var dirname = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : process.cwd();
+
+  return (0, _resolveFromPossibleNames2.default)((0, _getPossiblePluginNames2.default)(pluginName), dirname);
+}
+module.exports = exports["default"];
+}).call(this,require('_process'))
+},{"./get-possible-plugin-names":7,"./resolve-from-possible-names":11,"_process":525}],13:[function(require,module,exports){
+(function (process){
+"use strict";
+
+exports.__esModule = true;
+exports.default = resolvePreset;
+
+var _resolveFromPossibleNames = require("./resolve-from-possible-names");
+
+var _resolveFromPossibleNames2 = _interopRequireDefault(_resolveFromPossibleNames);
+
+var _getPossiblePresetNames = require("./get-possible-preset-names");
+
+var _getPossiblePresetNames2 = _interopRequireDefault(_getPossiblePresetNames);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function resolvePreset(presetName) {
+  var dirname = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : process.cwd();
+
+  return (0, _resolveFromPossibleNames2.default)((0, _getPossiblePresetNames2.default)(presetName), dirname);
+}
+module.exports = exports["default"];
+}).call(this,require('_process'))
+},{"./get-possible-preset-names":8,"./resolve-from-possible-names":11,"_process":525}],14:[function(require,module,exports){
+(function (process){
+"use strict";
+
+exports.__esModule = true;
+
+var _typeof2 = require("babel-runtime/helpers/typeof");
+
+var _typeof3 = _interopRequireDefault(_typeof2);
+
+exports.default = function (loc) {
+  var relative = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : process.cwd();
+
+  if ((typeof _module2.default === "undefined" ? "undefined" : (0, _typeof3.default)(_module2.default)) === "object") return null;
+
+  var relativeMod = relativeModules[relative];
+
+  if (!relativeMod) {
+    relativeMod = new _module2.default();
+
+    var filename = _path2.default.join(relative, ".babelrc");
+    relativeMod.id = filename;
+    relativeMod.filename = filename;
+
+    relativeMod.paths = _module2.default._nodeModulePaths(relative);
+    relativeModules[relative] = relativeMod;
+  }
+
+  try {
+    return _module2.default._resolveFilename(loc, relativeMod);
+  } catch (err) {
+    return null;
+  }
+};
+
+var _module = require("module");
+
+var _module2 = _interopRequireDefault(_module);
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var relativeModules = {};
+
+module.exports = exports["default"];
+}).call(this,require('_process'))
+},{"_process":525,"babel-runtime/helpers/typeof":113,"module":159,"path":522}],15:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _map = require("babel-runtime/core-js/map");
+
+var _map2 = _interopRequireDefault(_map);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require("babel-runtime/helpers/inherits");
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var Store = function (_Map) {
+  (0, _inherits3.default)(Store, _Map);
+
+  function Store() {
+    (0, _classCallCheck3.default)(this, Store);
+
+    var _this = (0, _possibleConstructorReturn3.default)(this, _Map.call(this));
+
+    _this.dynamicData = {};
+    return _this;
+  }
+
+  Store.prototype.setDynamic = function setDynamic(key, fn) {
+    this.dynamicData[key] = fn;
+  };
+
+  Store.prototype.get = function get(key) {
+    if (this.has(key)) {
+      return _Map.prototype.get.call(this, key);
+    } else {
+      if (Object.prototype.hasOwnProperty.call(this.dynamicData, key)) {
+        var val = this.dynamicData[key]();
+        this.set(key, val);
+        return val;
+      }
+    }
+  };
+
+  return Store;
+}(_map2.default);
+
+exports.default = Store;
+module.exports = exports["default"];
+},{"babel-runtime/core-js/map":97,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/inherits":110,"babel-runtime/helpers/possibleConstructorReturn":112}],16:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (whitelist) {
+  var outputType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "global";
+
+  var namespace = t.identifier("babelHelpers");
+
+  var builder = function builder(body) {
+    return buildHelpers(body, namespace, whitelist);
+  };
+
+  var tree = void 0;
+
+  var build = {
+    global: buildGlobal,
+    umd: buildUmd,
+    var: buildVar
+  }[outputType];
+
+  if (build) {
+    tree = build(namespace, builder);
+  } else {
+    throw new Error(messages.get("unsupportedOutputType", outputType));
+  }
+
+  return (0, _babelGenerator2.default)(tree).code;
+};
+
+var _babelHelpers = require("babel-helpers");
+
+var helpers = _interopRequireWildcard(_babelHelpers);
+
+var _babelGenerator = require("babel-generator");
+
+var _babelGenerator2 = _interopRequireDefault(_babelGenerator);
+
+var _babelMessages = require("babel-messages");
+
+var messages = _interopRequireWildcard(_babelMessages);
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+var buildUmdWrapper = (0, _babelTemplate2.default)("\n  (function (root, factory) {\n    if (typeof define === \"function\" && define.amd) {\n      define(AMD_ARGUMENTS, factory);\n    } else if (typeof exports === \"object\") {\n      factory(COMMON_ARGUMENTS);\n    } else {\n      factory(BROWSER_ARGUMENTS);\n    }\n  })(UMD_ROOT, function (FACTORY_PARAMETERS) {\n    FACTORY_BODY\n  });\n");
+
+function buildGlobal(namespace, builder) {
+  var body = [];
+  var container = t.functionExpression(null, [t.identifier("global")], t.blockStatement(body));
+  var tree = t.program([t.expressionStatement(t.callExpression(container, [helpers.get("selfGlobal")]))]);
+
+  body.push(t.variableDeclaration("var", [t.variableDeclarator(namespace, t.assignmentExpression("=", t.memberExpression(t.identifier("global"), namespace), t.objectExpression([])))]));
+
+  builder(body);
+
+  return tree;
+}
+
+function buildUmd(namespace, builder) {
+  var body = [];
+  body.push(t.variableDeclaration("var", [t.variableDeclarator(namespace, t.identifier("global"))]));
+
+  builder(body);
+
+  return t.program([buildUmdWrapper({
+    FACTORY_PARAMETERS: t.identifier("global"),
+    BROWSER_ARGUMENTS: t.assignmentExpression("=", t.memberExpression(t.identifier("root"), namespace), t.objectExpression([])),
+    COMMON_ARGUMENTS: t.identifier("exports"),
+    AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
+    FACTORY_BODY: body,
+    UMD_ROOT: t.identifier("this")
+  })]);
+}
+
+function buildVar(namespace, builder) {
+  var body = [];
+  body.push(t.variableDeclaration("var", [t.variableDeclarator(namespace, t.objectExpression([]))]));
+  builder(body);
+  body.push(t.expressionStatement(namespace));
+  return t.program(body);
+}
+
+function buildHelpers(body, namespace, whitelist) {
+  helpers.list.forEach(function (name) {
+    if (whitelist && whitelist.indexOf(name) < 0) return;
+
+    var key = t.identifier(name);
+    body.push(t.expressionStatement(t.assignmentExpression("=", t.memberExpression(namespace, key), helpers.get(name))));
+  });
+}
+module.exports = exports["default"];
+},{"babel-generator":44,"babel-helpers":60,"babel-messages":61,"babel-template":114,"babel-types":151}],17:[function(require,module,exports){
+(function (process){
+"use strict";
+
+exports.__esModule = true;
+exports.File = undefined;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _create = require("babel-runtime/core-js/object/create");
+
+var _create2 = _interopRequireDefault(_create);
+
+var _assign = require("babel-runtime/core-js/object/assign");
+
+var _assign2 = _interopRequireDefault(_assign);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require("babel-runtime/helpers/inherits");
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _babelHelpers = require("babel-helpers");
+
+var _babelHelpers2 = _interopRequireDefault(_babelHelpers);
+
+var _metadata = require("./metadata");
+
+var metadataVisitor = _interopRequireWildcard(_metadata);
+
+var _convertSourceMap = require("convert-source-map");
+
+var _convertSourceMap2 = _interopRequireDefault(_convertSourceMap);
+
+var _optionManager = require("./options/option-manager");
+
+var _optionManager2 = _interopRequireDefault(_optionManager);
+
+var _pluginPass = require("../plugin-pass");
+
+var _pluginPass2 = _interopRequireDefault(_pluginPass);
+
+var _babelTraverse = require("babel-traverse");
+
+var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
+
+var _sourceMap = require("source-map");
+
+var _sourceMap2 = _interopRequireDefault(_sourceMap);
+
+var _babelGenerator = require("babel-generator");
+
+var _babelGenerator2 = _interopRequireDefault(_babelGenerator);
+
+var _babelCodeFrame = require("babel-code-frame");
+
+var _babelCodeFrame2 = _interopRequireDefault(_babelCodeFrame);
+
+var _defaults = require("lodash/defaults");
+
+var _defaults2 = _interopRequireDefault(_defaults);
+
+var _logger = require("./logger");
+
+var _logger2 = _interopRequireDefault(_logger);
+
+var _store = require("../../store");
+
+var _store2 = _interopRequireDefault(_store);
+
+var _babylon = require("babylon");
+
+var _util = require("../../util");
+
+var util = _interopRequireWildcard(_util);
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+var _resolve = require("../../helpers/resolve");
+
+var _resolve2 = _interopRequireDefault(_resolve);
+
+var _blockHoist = require("../internal-plugins/block-hoist");
+
+var _blockHoist2 = _interopRequireDefault(_blockHoist);
+
+var _shadowFunctions = require("../internal-plugins/shadow-functions");
+
+var _shadowFunctions2 = _interopRequireDefault(_shadowFunctions);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var shebangRegex = /^#!.*/;
+
+var INTERNAL_PLUGINS = [[_blockHoist2.default], [_shadowFunctions2.default]];
+
+var errorVisitor = {
+  enter: function enter(path, state) {
+    var loc = path.node.loc;
+    if (loc) {
+      state.loc = loc;
+      path.stop();
+    }
+  }
+};
+
+var File = function (_Store) {
+  (0, _inherits3.default)(File, _Store);
+
+  function File() {
+    var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+    var pipeline = arguments[1];
+    (0, _classCallCheck3.default)(this, File);
+
+    var _this = (0, _possibleConstructorReturn3.default)(this, _Store.call(this));
+
+    _this.pipeline = pipeline;
+
+    _this.log = new _logger2.default(_this, opts.filename || "unknown");
+    _this.opts = _this.initOptions(opts);
+
+    _this.parserOpts = {
+      sourceType: _this.opts.sourceType,
+      sourceFileName: _this.opts.filename,
+      plugins: []
+    };
+
+    _this.pluginVisitors = [];
+    _this.pluginPasses = [];
+
+    _this.buildPluginsForOptions(_this.opts);
+
+    if (_this.opts.passPerPreset) {
+      _this.perPresetOpts = [];
+      _this.opts.presets.forEach(function (presetOpts) {
+        var perPresetOpts = (0, _assign2.default)((0, _create2.default)(_this.opts), presetOpts);
+        _this.perPresetOpts.push(perPresetOpts);
+        _this.buildPluginsForOptions(perPresetOpts);
+      });
+    }
+
+    _this.metadata = {
+      usedHelpers: [],
+      marked: [],
+      modules: {
+        imports: [],
+        exports: {
+          exported: [],
+          specifiers: []
+        }
+      }
+    };
+
+    _this.dynamicImportTypes = {};
+    _this.dynamicImportIds = {};
+    _this.dynamicImports = [];
+    _this.declarations = {};
+    _this.usedHelpers = {};
+
+    _this.path = null;
+    _this.ast = {};
+
+    _this.code = "";
+    _this.shebang = "";
+
+    _this.hub = new _babelTraverse.Hub(_this);
+    return _this;
+  }
+
+  File.prototype.getMetadata = function getMetadata() {
+    var has = false;
+    for (var _iterator = this.ast.program.body, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var node = _ref;
+
+      if (t.isModuleDeclaration(node)) {
+        has = true;
+        break;
+      }
+    }
+    if (has) {
+      this.path.traverse(metadataVisitor, this);
+    }
+  };
+
+  File.prototype.initOptions = function initOptions(opts) {
+    opts = new _optionManager2.default(this.log, this.pipeline).init(opts);
+
+    if (opts.inputSourceMap) {
+      opts.sourceMaps = true;
+    }
+
+    if (opts.moduleId) {
+      opts.moduleIds = true;
+    }
+
+    opts.basename = _path2.default.basename(opts.filename, _path2.default.extname(opts.filename));
+
+    opts.ignore = util.arrayify(opts.ignore, util.regexify);
+
+    if (opts.only) opts.only = util.arrayify(opts.only, util.regexify);
+
+    (0, _defaults2.default)(opts, {
+      moduleRoot: opts.sourceRoot
+    });
+
+    (0, _defaults2.default)(opts, {
+      sourceRoot: opts.moduleRoot
+    });
+
+    (0, _defaults2.default)(opts, {
+      filenameRelative: opts.filename
+    });
+
+    var basenameRelative = _path2.default.basename(opts.filenameRelative);
+
+    (0, _defaults2.default)(opts, {
+      sourceFileName: basenameRelative,
+      sourceMapTarget: basenameRelative
+    });
+
+    return opts;
+  };
+
+  File.prototype.buildPluginsForOptions = function buildPluginsForOptions(opts) {
+    if (!Array.isArray(opts.plugins)) {
+      return;
+    }
+
+    var plugins = opts.plugins.concat(INTERNAL_PLUGINS);
+    var currentPluginVisitors = [];
+    var currentPluginPasses = [];
+
+    for (var _iterator2 = plugins, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref2;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref2 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref2 = _i2.value;
+      }
+
+      var ref = _ref2;
+      var plugin = ref[0],
+          pluginOpts = ref[1];
+
+
+      currentPluginVisitors.push(plugin.visitor);
+      currentPluginPasses.push(new _pluginPass2.default(this, plugin, pluginOpts));
+
+      if (plugin.manipulateOptions) {
+        plugin.manipulateOptions(opts, this.parserOpts, this);
+      }
+    }
+
+    this.pluginVisitors.push(currentPluginVisitors);
+    this.pluginPasses.push(currentPluginPasses);
+  };
+
+  File.prototype.getModuleName = function getModuleName() {
+    var opts = this.opts;
+    if (!opts.moduleIds) {
+      return null;
+    }
+
+    if (opts.moduleId != null && !opts.getModuleId) {
+      return opts.moduleId;
+    }
+
+    var filenameRelative = opts.filenameRelative;
+    var moduleName = "";
+
+    if (opts.moduleRoot != null) {
+      moduleName = opts.moduleRoot + "/";
+    }
+
+    if (!opts.filenameRelative) {
+      return moduleName + opts.filename.replace(/^\//, "");
+    }
+
+    if (opts.sourceRoot != null) {
+      var sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?");
+      filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
+    }
+
+    filenameRelative = filenameRelative.replace(/\.(\w*?)$/, "");
+
+    moduleName += filenameRelative;
+
+    moduleName = moduleName.replace(/\\/g, "/");
+
+    if (opts.getModuleId) {
+      return opts.getModuleId(moduleName) || moduleName;
+    } else {
+      return moduleName;
+    }
+  };
+
+  File.prototype.resolveModuleSource = function resolveModuleSource(source) {
+    var resolveModuleSource = this.opts.resolveModuleSource;
+    if (resolveModuleSource) source = resolveModuleSource(source, this.opts.filename);
+    return source;
+  };
+
+  File.prototype.addImport = function addImport(source, imported) {
+    var name = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : imported;
+
+    var alias = source + ":" + imported;
+    var id = this.dynamicImportIds[alias];
+
+    if (!id) {
+      source = this.resolveModuleSource(source);
+      id = this.dynamicImportIds[alias] = this.scope.generateUidIdentifier(name);
+
+      var specifiers = [];
+
+      if (imported === "*") {
+        specifiers.push(t.importNamespaceSpecifier(id));
+      } else if (imported === "default") {
+        specifiers.push(t.importDefaultSpecifier(id));
+      } else {
+        specifiers.push(t.importSpecifier(id, t.identifier(imported)));
+      }
+
+      var declar = t.importDeclaration(specifiers, t.stringLiteral(source));
+      declar._blockHoist = 3;
+
+      this.path.unshiftContainer("body", declar);
+    }
+
+    return id;
+  };
+
+  File.prototype.addHelper = function addHelper(name) {
+    var declar = this.declarations[name];
+    if (declar) return declar;
+
+    if (!this.usedHelpers[name]) {
+      this.metadata.usedHelpers.push(name);
+      this.usedHelpers[name] = true;
+    }
+
+    var generator = this.get("helperGenerator");
+    var runtime = this.get("helpersNamespace");
+    if (generator) {
+      var res = generator(name);
+      if (res) return res;
+    } else if (runtime) {
+      return t.memberExpression(runtime, t.identifier(name));
+    }
+
+    var ref = (0, _babelHelpers2.default)(name);
+    var uid = this.declarations[name] = this.scope.generateUidIdentifier(name);
+
+    if (t.isFunctionExpression(ref) && !ref.id) {
+      ref.body._compact = true;
+      ref._generated = true;
+      ref.id = uid;
+      ref.type = "FunctionDeclaration";
+      this.path.unshiftContainer("body", ref);
+    } else {
+      ref._compact = true;
+      this.scope.push({
+        id: uid,
+        init: ref,
+        unique: true
+      });
+    }
+
+    return uid;
+  };
+
+  File.prototype.addTemplateObject = function addTemplateObject(helperName, strings, raw) {
+    var stringIds = raw.elements.map(function (string) {
+      return string.value;
+    });
+    var name = helperName + "_" + raw.elements.length + "_" + stringIds.join(",");
+
+    var declar = this.declarations[name];
+    if (declar) return declar;
+
+    var uid = this.declarations[name] = this.scope.generateUidIdentifier("templateObject");
+
+    var helperId = this.addHelper(helperName);
+    var init = t.callExpression(helperId, [strings, raw]);
+    init._compact = true;
+    this.scope.push({
+      id: uid,
+      init: init,
+      _blockHoist: 1.9 });
+    return uid;
+  };
+
+  File.prototype.buildCodeFrameError = function buildCodeFrameError(node, msg) {
+    var Error = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : SyntaxError;
+
+    var loc = node && (node.loc || node._loc);
+
+    var err = new Error(msg);
+
+    if (loc) {
+      err.loc = loc.start;
+    } else {
+      (0, _babelTraverse2.default)(node, errorVisitor, this.scope, err);
+
+      err.message += " (This is an error on an internal node. Probably an internal error";
+
+      if (err.loc) {
+        err.message += ". Location has been estimated.";
+      }
+
+      err.message += ")";
+    }
+
+    return err;
+  };
+
+  File.prototype.mergeSourceMap = function mergeSourceMap(map) {
+    var inputMap = this.opts.inputSourceMap;
+
+    if (inputMap) {
+      var inputMapConsumer = new _sourceMap2.default.SourceMapConsumer(inputMap);
+      var outputMapConsumer = new _sourceMap2.default.SourceMapConsumer(map);
+
+      var mergedGenerator = new _sourceMap2.default.SourceMapGenerator({
+        file: inputMapConsumer.file,
+        sourceRoot: inputMapConsumer.sourceRoot
+      });
+
+      var source = outputMapConsumer.sources[0];
+
+      inputMapConsumer.eachMapping(function (mapping) {
+        var generatedPosition = outputMapConsumer.generatedPositionFor({
+          line: mapping.generatedLine,
+          column: mapping.generatedColumn,
+          source: source
+        });
+        if (generatedPosition.column != null) {
+          mergedGenerator.addMapping({
+            source: mapping.source,
+
+            original: mapping.source == null ? null : {
+              line: mapping.originalLine,
+              column: mapping.originalColumn
+            },
+
+            generated: generatedPosition
+          });
+        }
+      });
+
+      var mergedMap = mergedGenerator.toJSON();
+      inputMap.mappings = mergedMap.mappings;
+      return inputMap;
+    } else {
+      return map;
+    }
+  };
+
+  File.prototype.parse = function parse(code) {
+    var parseCode = _babylon.parse;
+    var parserOpts = this.opts.parserOpts;
+
+    if (parserOpts) {
+      parserOpts = (0, _assign2.default)({}, this.parserOpts, parserOpts);
+
+      if (parserOpts.parser) {
+        if (typeof parserOpts.parser === "string") {
+          var dirname = _path2.default.dirname(this.opts.filename) || process.cwd();
+          var parser = (0, _resolve2.default)(parserOpts.parser, dirname);
+          if (parser) {
+            parseCode = require(parser).parse;
+          } else {
+            throw new Error("Couldn't find parser " + parserOpts.parser + " with \"parse\" method " + ("relative to directory " + dirname));
+          }
+        } else {
+          parseCode = parserOpts.parser;
+        }
+
+        parserOpts.parser = {
+          parse: function parse(source) {
+            return (0, _babylon.parse)(source, parserOpts);
+          }
+        };
+      }
+    }
+
+    this.log.debug("Parse start");
+    var ast = parseCode(code, parserOpts || this.parserOpts);
+    this.log.debug("Parse stop");
+    return ast;
+  };
+
+  File.prototype._addAst = function _addAst(ast) {
+    this.path = _babelTraverse.NodePath.get({
+      hub: this.hub,
+      parentPath: null,
+      parent: ast,
+      container: ast,
+      key: "program"
+    }).setContext();
+    this.scope = this.path.scope;
+    this.ast = ast;
+    this.getMetadata();
+  };
+
+  File.prototype.addAst = function addAst(ast) {
+    this.log.debug("Start set AST");
+    this._addAst(ast);
+    this.log.debug("End set AST");
+  };
+
+  File.prototype.transform = function transform() {
+    for (var i = 0; i < this.pluginPasses.length; i++) {
+      var pluginPasses = this.pluginPasses[i];
+      this.call("pre", pluginPasses);
+      this.log.debug("Start transform traverse");
+
+      var visitor = _babelTraverse2.default.visitors.merge(this.pluginVisitors[i], pluginPasses, this.opts.wrapPluginVisitorMethod);
+      (0, _babelTraverse2.default)(this.ast, visitor, this.scope);
+
+      this.log.debug("End transform traverse");
+      this.call("post", pluginPasses);
+    }
+
+    return this.generate();
+  };
+
+  File.prototype.wrap = function wrap(code, callback) {
+    code = code + "";
+
+    try {
+      if (this.shouldIgnore()) {
+        return this.makeResult({ code: code, ignored: true });
+      } else {
+        return callback();
+      }
+    } catch (err) {
+      if (err._babel) {
+        throw err;
+      } else {
+        err._babel = true;
+      }
+
+      var message = err.message = this.opts.filename + ": " + err.message;
+
+      var loc = err.loc;
+      if (loc) {
+        err.codeFrame = (0, _babelCodeFrame2.default)(code, loc.line, loc.column + 1, this.opts);
+        message += "\n" + err.codeFrame;
+      }
+
+      if (process.browser) {
+        err.message = message;
+      }
+
+      if (err.stack) {
+        var newStack = err.stack.replace(err.message, message);
+        err.stack = newStack;
+      }
+
+      throw err;
+    }
+  };
+
+  File.prototype.addCode = function addCode(code) {
+    code = (code || "") + "";
+    code = this.parseInputSourceMap(code);
+    this.code = code;
+  };
+
+  File.prototype.parseCode = function parseCode() {
+    this.parseShebang();
+    var ast = this.parse(this.code);
+    this.addAst(ast);
+  };
+
+  File.prototype.shouldIgnore = function shouldIgnore() {
+    var opts = this.opts;
+    return util.shouldIgnore(opts.filename, opts.ignore, opts.only);
+  };
+
+  File.prototype.call = function call(key, pluginPasses) {
+    for (var _iterator3 = pluginPasses, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+      var _ref3;
+
+      if (_isArray3) {
+        if (_i3 >= _iterator3.length) break;
+        _ref3 = _iterator3[_i3++];
+      } else {
+        _i3 = _iterator3.next();
+        if (_i3.done) break;
+        _ref3 = _i3.value;
+      }
+
+      var pass = _ref3;
+
+      var plugin = pass.plugin;
+      var fn = plugin[key];
+      if (fn) fn.call(pass, this);
+    }
+  };
+
+  File.prototype.parseInputSourceMap = function parseInputSourceMap(code) {
+    var opts = this.opts;
+
+    if (opts.inputSourceMap !== false) {
+      var inputMap = _convertSourceMap2.default.fromSource(code);
+      if (inputMap) {
+        opts.inputSourceMap = inputMap.toObject();
+        code = _convertSourceMap2.default.removeComments(code);
+      }
+    }
+
+    return code;
+  };
+
+  File.prototype.parseShebang = function parseShebang() {
+    var shebangMatch = shebangRegex.exec(this.code);
+    if (shebangMatch) {
+      this.shebang = shebangMatch[0];
+      this.code = this.code.replace(shebangRegex, "");
+    }
+  };
+
+  File.prototype.makeResult = function makeResult(_ref4) {
+    var code = _ref4.code,
+        map = _ref4.map,
+        ast = _ref4.ast,
+        ignored = _ref4.ignored;
+
+    var result = {
+      metadata: null,
+      options: this.opts,
+      ignored: !!ignored,
+      code: null,
+      ast: null,
+      map: map || null
+    };
+
+    if (this.opts.code) {
+      result.code = code;
+    }
+
+    if (this.opts.ast) {
+      result.ast = ast;
+    }
+
+    if (this.opts.metadata) {
+      result.metadata = this.metadata;
+    }
+
+    return result;
+  };
+
+  File.prototype.generate = function generate() {
+    var opts = this.opts;
+    var ast = this.ast;
+
+    var result = { ast: ast };
+    if (!opts.code) return this.makeResult(result);
+
+    var gen = _babelGenerator2.default;
+    if (opts.generatorOpts.generator) {
+      gen = opts.generatorOpts.generator;
+
+      if (typeof gen === "string") {
+        var dirname = _path2.default.dirname(this.opts.filename) || process.cwd();
+        var generator = (0, _resolve2.default)(gen, dirname);
+        if (generator) {
+          gen = require(generator).print;
+        } else {
+          throw new Error("Couldn't find generator " + gen + " with \"print\" method relative " + ("to directory " + dirname));
+        }
+      }
+    }
+
+    this.log.debug("Generation start");
+
+    var _result = gen(ast, opts.generatorOpts ? (0, _assign2.default)(opts, opts.generatorOpts) : opts, this.code);
+    result.code = _result.code;
+    result.map = _result.map;
+
+    this.log.debug("Generation end");
+
+    if (this.shebang) {
+      result.code = this.shebang + "\n" + result.code;
+    }
+
+    if (result.map) {
+      result.map = this.mergeSourceMap(result.map);
+    }
+
+    if (opts.sourceMaps === "inline" || opts.sourceMaps === "both") {
+      result.code += "\n" + _convertSourceMap2.default.fromObject(result.map).toComment();
+    }
+
+    if (opts.sourceMaps === "inline") {
+      result.map = null;
+    }
+
+    return this.makeResult(result);
+  };
+
+  return File;
+}(_store2.default);
+
+exports.default = File;
+exports.File = File;
+}).call(this,require('_process'))
+},{"../../helpers/resolve":14,"../../store":15,"../../util":31,"../internal-plugins/block-hoist":26,"../internal-plugins/shadow-functions":27,"../plugin-pass":29,"./logger":18,"./metadata":19,"./options/option-manager":23,"_process":525,"babel-code-frame":4,"babel-generator":44,"babel-helpers":60,"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/object/assign":99,"babel-runtime/core-js/object/create":100,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/inherits":110,"babel-runtime/helpers/possibleConstructorReturn":112,"babel-traverse":118,"babel-types":151,"babylon":155,"convert-source-map":163,"lodash/defaults":470,"path":522,"source-map":552}],18:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _node = require("debug/node");
+
+var _node2 = _interopRequireDefault(_node);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var verboseDebug = (0, _node2.default)("babel:verbose");
+var generalDebug = (0, _node2.default)("babel");
+
+var seenDeprecatedMessages = [];
+
+var Logger = function () {
+  function Logger(file, filename) {
+    (0, _classCallCheck3.default)(this, Logger);
+
+    this.filename = filename;
+    this.file = file;
+  }
+
+  Logger.prototype._buildMessage = function _buildMessage(msg) {
+    var parts = "[BABEL] " + this.filename;
+    if (msg) parts += ": " + msg;
+    return parts;
+  };
+
+  Logger.prototype.warn = function warn(msg) {
+    console.warn(this._buildMessage(msg));
+  };
+
+  Logger.prototype.error = function error(msg) {
+    var Constructor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Error;
+
+    throw new Constructor(this._buildMessage(msg));
+  };
+
+  Logger.prototype.deprecate = function deprecate(msg) {
+    if (this.file.opts && this.file.opts.suppressDeprecationMessages) return;
+
+    msg = this._buildMessage(msg);
+
+    if (seenDeprecatedMessages.indexOf(msg) >= 0) return;
+
+    seenDeprecatedMessages.push(msg);
+
+    console.error(msg);
+  };
+
+  Logger.prototype.verbose = function verbose(msg) {
+    if (verboseDebug.enabled) verboseDebug(this._buildMessage(msg));
+  };
+
+  Logger.prototype.debug = function debug(msg) {
+    if (generalDebug.enabled) generalDebug(this._buildMessage(msg));
+  };
+
+  Logger.prototype.deopt = function deopt(node, msg) {
+    this.debug(msg);
+  };
+
+  return Logger;
+}();
+
+exports.default = Logger;
+module.exports = exports["default"];
+},{"babel-runtime/helpers/classCallCheck":109,"debug/node":278}],19:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.ImportDeclaration = exports.ModuleDeclaration = undefined;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.ExportDeclaration = ExportDeclaration;
+exports.Scope = Scope;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var ModuleDeclaration = exports.ModuleDeclaration = {
+  enter: function enter(path, file) {
+    var node = path.node;
+
+    if (node.source) {
+      node.source.value = file.resolveModuleSource(node.source.value);
+    }
+  }
+};
+
+var ImportDeclaration = exports.ImportDeclaration = {
+  exit: function exit(path, file) {
+    var node = path.node;
+
+
+    var specifiers = [];
+    var imported = [];
+    file.metadata.modules.imports.push({
+      source: node.source.value,
+      imported: imported,
+      specifiers: specifiers
+    });
+
+    for (var _iterator = path.get("specifiers"), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var specifier = _ref;
+
+      var local = specifier.node.local.name;
+
+      if (specifier.isImportDefaultSpecifier()) {
+        imported.push("default");
+        specifiers.push({
+          kind: "named",
+          imported: "default",
+          local: local
+        });
+      }
+
+      if (specifier.isImportSpecifier()) {
+        var importedName = specifier.node.imported.name;
+        imported.push(importedName);
+        specifiers.push({
+          kind: "named",
+          imported: importedName,
+          local: local
+        });
+      }
+
+      if (specifier.isImportNamespaceSpecifier()) {
+        imported.push("*");
+        specifiers.push({
+          kind: "namespace",
+          local: local
+        });
+      }
+    }
+  }
+};
+
+function ExportDeclaration(path, file) {
+  var node = path.node;
+
+
+  var source = node.source ? node.source.value : null;
+  var exports = file.metadata.modules.exports;
+
+  var declar = path.get("declaration");
+  if (declar.isStatement()) {
+    var bindings = declar.getBindingIdentifiers();
+
+    for (var name in bindings) {
+      exports.exported.push(name);
+      exports.specifiers.push({
+        kind: "local",
+        local: name,
+        exported: path.isExportDefaultDeclaration() ? "default" : name
+      });
+    }
+  }
+
+  if (path.isExportNamedDeclaration() && node.specifiers) {
+    for (var _iterator2 = node.specifiers, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref2;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref2 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref2 = _i2.value;
+      }
+
+      var specifier = _ref2;
+
+      var exported = specifier.exported.name;
+      exports.exported.push(exported);
+
+      if (t.isExportDefaultSpecifier(specifier)) {
+        exports.specifiers.push({
+          kind: "external",
+          local: exported,
+          exported: exported,
+          source: source
+        });
+      }
+
+      if (t.isExportNamespaceSpecifier(specifier)) {
+        exports.specifiers.push({
+          kind: "external-namespace",
+          exported: exported,
+          source: source
+        });
+      }
+
+      var local = specifier.local;
+      if (!local) continue;
+
+      if (source) {
+        exports.specifiers.push({
+          kind: "external",
+          local: local.name,
+          exported: exported,
+          source: source
+        });
+      }
+
+      if (!source) {
+        exports.specifiers.push({
+          kind: "local",
+          local: local.name,
+          exported: exported
+        });
+      }
+    }
+  }
+
+  if (path.isExportAllDeclaration()) {
+    exports.specifiers.push({
+      kind: "external-all",
+      source: source
+    });
+  }
+}
+
+function Scope(path) {
+  path.skip();
+}
+},{"babel-runtime/core-js/get-iterator":95,"babel-types":151}],20:[function(require,module,exports){
+(function (process){
+"use strict";
+
+exports.__esModule = true;
+
+var _assign = require("babel-runtime/core-js/object/assign");
+
+var _assign2 = _interopRequireDefault(_assign);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+exports.default = buildConfigChain;
+
+var _resolve = require("../../../helpers/resolve");
+
+var _resolve2 = _interopRequireDefault(_resolve);
+
+var _json = require("json5");
+
+var _json2 = _interopRequireDefault(_json);
+
+var _pathIsAbsolute = require("path-is-absolute");
+
+var _pathIsAbsolute2 = _interopRequireDefault(_pathIsAbsolute);
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+var _fs = require("fs");
+
+var _fs2 = _interopRequireDefault(_fs);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var existsCache = {};
+var jsonCache = {};
+
+var BABELIGNORE_FILENAME = ".babelignore";
+var BABELRC_FILENAME = ".babelrc";
+var PACKAGE_FILENAME = "package.json";
+
+function exists(filename) {
+  var cached = existsCache[filename];
+  if (cached == null) {
+    return existsCache[filename] = _fs2.default.existsSync(filename);
+  } else {
+    return cached;
+  }
+}
+
+function buildConfigChain() {
+  var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+  var log = arguments[1];
+
+  var filename = opts.filename;
+  var builder = new ConfigChainBuilder(log);
+
+  if (opts.babelrc !== false) {
+    builder.findConfigs(filename);
+  }
+
+  builder.mergeConfig({
+    options: opts,
+    alias: "base",
+    dirname: filename && _path2.default.dirname(filename)
+  });
+
+  return builder.configs;
+}
+
+var ConfigChainBuilder = function () {
+  function ConfigChainBuilder(log) {
+    (0, _classCallCheck3.default)(this, ConfigChainBuilder);
+
+    this.resolvedConfigs = [];
+    this.configs = [];
+    this.log = log;
+  }
+
+  ConfigChainBuilder.prototype.findConfigs = function findConfigs(loc) {
+    if (!loc) return;
+
+    if (!(0, _pathIsAbsolute2.default)(loc)) {
+      loc = _path2.default.join(process.cwd(), loc);
+    }
+
+    var foundConfig = false;
+    var foundIgnore = false;
+
+    while (loc !== (loc = _path2.default.dirname(loc))) {
+      if (!foundConfig) {
+        var configLoc = _path2.default.join(loc, BABELRC_FILENAME);
+        if (exists(configLoc)) {
+          this.addConfig(configLoc);
+          foundConfig = true;
+        }
+
+        var pkgLoc = _path2.default.join(loc, PACKAGE_FILENAME);
+        if (!foundConfig && exists(pkgLoc)) {
+          foundConfig = this.addConfig(pkgLoc, "babel", JSON);
+        }
+      }
+
+      if (!foundIgnore) {
+        var ignoreLoc = _path2.default.join(loc, BABELIGNORE_FILENAME);
+        if (exists(ignoreLoc)) {
+          this.addIgnoreConfig(ignoreLoc);
+          foundIgnore = true;
+        }
+      }
+
+      if (foundIgnore && foundConfig) return;
+    }
+  };
+
+  ConfigChainBuilder.prototype.addIgnoreConfig = function addIgnoreConfig(loc) {
+    var file = _fs2.default.readFileSync(loc, "utf8");
+    var lines = file.split("\n");
+
+    lines = lines.map(function (line) {
+      return line.replace(/#(.*?)$/, "").trim();
+    }).filter(function (line) {
+      return !!line;
+    });
+
+    if (lines.length) {
+      this.mergeConfig({
+        options: { ignore: lines },
+        alias: loc,
+        dirname: _path2.default.dirname(loc)
+      });
+    }
+  };
+
+  ConfigChainBuilder.prototype.addConfig = function addConfig(loc, key) {
+    var json = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _json2.default;
+
+    if (this.resolvedConfigs.indexOf(loc) >= 0) {
+      return false;
+    }
+
+    this.resolvedConfigs.push(loc);
+
+    var content = _fs2.default.readFileSync(loc, "utf8");
+    var options = void 0;
+
+    try {
+      options = jsonCache[content] = jsonCache[content] || json.parse(content);
+      if (key) options = options[key];
+    } catch (err) {
+      err.message = loc + ": Error while parsing JSON - " + err.message;
+      throw err;
+    }
+
+    this.mergeConfig({
+      options: options,
+      alias: loc,
+      dirname: _path2.default.dirname(loc)
+    });
+
+    return !!options;
+  };
+
+  ConfigChainBuilder.prototype.mergeConfig = function mergeConfig(_ref) {
+    var options = _ref.options,
+        alias = _ref.alias,
+        loc = _ref.loc,
+        dirname = _ref.dirname;
+
+    if (!options) {
+      return false;
+    }
+
+    options = (0, _assign2.default)({}, options);
+
+    dirname = dirname || process.cwd();
+    loc = loc || alias;
+
+    if (options.extends) {
+      var extendsLoc = (0, _resolve2.default)(options.extends, dirname);
+      if (extendsLoc) {
+        this.addConfig(extendsLoc);
+      } else {
+        if (this.log) this.log.error("Couldn't resolve extends clause of " + options.extends + " in " + alias);
+      }
+      delete options.extends;
+    }
+
+    this.configs.push({
+      options: options,
+      alias: alias,
+      loc: loc,
+      dirname: dirname
+    });
+
+    var envOpts = void 0;
+    var envKey = process.env.BABEL_ENV || process.env.NODE_ENV || "development";
+    if (options.env) {
+      envOpts = options.env[envKey];
+      delete options.env;
+    }
+
+    this.mergeConfig({
+      options: envOpts,
+      alias: alias + ".env." + envKey,
+      dirname: dirname
+    });
+  };
+
+  return ConfigChainBuilder;
+}();
+
+module.exports = exports["default"];
+}).call(this,require('_process'))
+},{"../../../helpers/resolve":14,"_process":525,"babel-runtime/core-js/object/assign":99,"babel-runtime/helpers/classCallCheck":109,"fs":159,"json5":297,"path":522,"path-is-absolute":523}],21:[function(require,module,exports){
+"use strict";
+
+module.exports = {
+  filename: {
+    type: "filename",
+    description: "filename to use when reading from stdin - this will be used in source-maps, errors etc",
+    default: "unknown",
+    shorthand: "f"
+  },
+
+  filenameRelative: {
+    hidden: true,
+    type: "string"
+  },
+
+  inputSourceMap: {
+    hidden: true
+  },
+
+  env: {
+    hidden: true,
+    default: {}
+  },
+
+  mode: {
+    description: "",
+    hidden: true
+  },
+
+  retainLines: {
+    type: "boolean",
+    default: false,
+    description: "retain line numbers - will result in really ugly code"
+  },
+
+  highlightCode: {
+    description: "enable/disable ANSI syntax highlighting of code frames (on by default)",
+    type: "boolean",
+    default: true
+  },
+
+  suppressDeprecationMessages: {
+    type: "boolean",
+    default: false,
+    hidden: true
+  },
+
+  presets: {
+    type: "list",
+    description: "",
+    default: []
+  },
+
+  plugins: {
+    type: "list",
+    default: [],
+    description: ""
+  },
+
+  ignore: {
+    type: "list",
+    description: "list of glob paths to **not** compile",
+    default: []
+  },
+
+  only: {
+    type: "list",
+    description: "list of glob paths to **only** compile"
+  },
+
+  code: {
+    hidden: true,
+    default: true,
+    type: "boolean"
+  },
+
+  metadata: {
+    hidden: true,
+    default: true,
+    type: "boolean"
+  },
+
+  ast: {
+    hidden: true,
+    default: true,
+    type: "boolean"
+  },
+
+  extends: {
+    type: "string",
+    hidden: true
+  },
+
+  comments: {
+    type: "boolean",
+    default: true,
+    description: "write comments to generated output (true by default)"
+  },
+
+  shouldPrintComment: {
+    hidden: true,
+    description: "optional callback to control whether a comment should be inserted, when this is used the comments option is ignored"
+  },
+
+  wrapPluginVisitorMethod: {
+    hidden: true,
+    description: "optional callback to wrap all visitor methods"
+  },
+
+  compact: {
+    type: "booleanString",
+    default: "auto",
+    description: "do not include superfluous whitespace characters and line terminators [true|false|auto]"
+  },
+
+  minified: {
+    type: "boolean",
+    default: false,
+    description: "save as much bytes when printing [true|false]"
+  },
+
+  sourceMap: {
+    alias: "sourceMaps",
+    hidden: true
+  },
+
+  sourceMaps: {
+    type: "booleanString",
+    description: "[true|false|inline]",
+    default: false,
+    shorthand: "s"
+  },
+
+  sourceMapTarget: {
+    type: "string",
+    description: "set `file` on returned source map"
+  },
+
+  sourceFileName: {
+    type: "string",
+    description: "set `sources[0]` on returned source map"
+  },
+
+  sourceRoot: {
+    type: "filename",
+    description: "the root from which all sources are relative"
+  },
+
+  babelrc: {
+    description: "Whether or not to look up .babelrc and .babelignore files",
+    type: "boolean",
+    default: true
+  },
+
+  sourceType: {
+    description: "",
+    default: "module"
+  },
+
+  auxiliaryCommentBefore: {
+    type: "string",
+    description: "print a comment before any injected non-user code"
+  },
+
+  auxiliaryCommentAfter: {
+    type: "string",
+    description: "print a comment after any injected non-user code"
+  },
+
+  resolveModuleSource: {
+    hidden: true
+  },
+
+  getModuleId: {
+    hidden: true
+  },
+
+  moduleRoot: {
+    type: "filename",
+    description: "optional prefix for the AMD module formatter that will be prepend to the filename on module definitions"
+  },
+
+  moduleIds: {
+    type: "boolean",
+    default: false,
+    shorthand: "M",
+    description: "insert an explicit id for modules"
+  },
+
+  moduleId: {
+    description: "specify a custom name for module ids",
+    type: "string"
+  },
+
+  passPerPreset: {
+    description: "Whether to spawn a traversal pass per a preset. By default all presets are merged.",
+    type: "boolean",
+    default: false,
+    hidden: true
+  },
+
+  parserOpts: {
+    description: "Options to pass into the parser, or to change parsers (parserOpts.parser)",
+    default: false
+  },
+
+  generatorOpts: {
+    description: "Options to pass into the generator, or to change generators (generatorOpts.generator)",
+    default: false
+  }
+};
+},{}],22:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.config = undefined;
+exports.normaliseOptions = normaliseOptions;
+
+var _parsers = require("./parsers");
+
+var parsers = _interopRequireWildcard(_parsers);
+
+var _config = require("./config");
+
+var _config2 = _interopRequireDefault(_config);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+exports.config = _config2.default;
+function normaliseOptions() {
+  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+  for (var key in options) {
+    var val = options[key];
+    if (val == null) continue;
+
+    var opt = _config2.default[key];
+    if (opt && opt.alias) opt = _config2.default[opt.alias];
+    if (!opt) continue;
+
+    var parser = parsers[opt.type];
+    if (parser) val = parser(val);
+
+    options[key] = val;
+  }
+
+  return options;
+}
+},{"./config":21,"./parsers":24}],23:[function(require,module,exports){
+(function (process){
+"use strict";
+
+exports.__esModule = true;
+
+var _objectWithoutProperties2 = require("babel-runtime/helpers/objectWithoutProperties");
+
+var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
+
+var _stringify = require("babel-runtime/core-js/json/stringify");
+
+var _stringify2 = _interopRequireDefault(_stringify);
+
+var _assign = require("babel-runtime/core-js/object/assign");
+
+var _assign2 = _interopRequireDefault(_assign);
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _typeof2 = require("babel-runtime/helpers/typeof");
+
+var _typeof3 = _interopRequireDefault(_typeof2);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _node = require("../../../api/node");
+
+var context = _interopRequireWildcard(_node);
+
+var _plugin2 = require("../../plugin");
+
+var _plugin3 = _interopRequireDefault(_plugin2);
+
+var _babelMessages = require("babel-messages");
+
+var messages = _interopRequireWildcard(_babelMessages);
+
+var _index = require("./index");
+
+var _resolvePlugin = require("../../../helpers/resolve-plugin");
+
+var _resolvePlugin2 = _interopRequireDefault(_resolvePlugin);
+
+var _resolvePreset = require("../../../helpers/resolve-preset");
+
+var _resolvePreset2 = _interopRequireDefault(_resolvePreset);
+
+var _cloneDeepWith = require("lodash/cloneDeepWith");
+
+var _cloneDeepWith2 = _interopRequireDefault(_cloneDeepWith);
+
+var _clone = require("lodash/clone");
+
+var _clone2 = _interopRequireDefault(_clone);
+
+var _merge = require("../../../helpers/merge");
+
+var _merge2 = _interopRequireDefault(_merge);
+
+var _config2 = require("./config");
+
+var _config3 = _interopRequireDefault(_config2);
+
+var _removed = require("./removed");
+
+var _removed2 = _interopRequireDefault(_removed);
+
+var _buildConfigChain = require("./build-config-chain");
+
+var _buildConfigChain2 = _interopRequireDefault(_buildConfigChain);
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var OptionManager = function () {
+  function OptionManager(log) {
+    (0, _classCallCheck3.default)(this, OptionManager);
+
+    this.resolvedConfigs = [];
+    this.options = OptionManager.createBareOptions();
+    this.log = log;
+  }
+
+  OptionManager.memoisePluginContainer = function memoisePluginContainer(fn, loc, i, alias) {
+    for (var _iterator = OptionManager.memoisedPlugins, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var cache = _ref;
+
+      if (cache.container === fn) return cache.plugin;
+    }
+
+    var obj = void 0;
+
+    if (typeof fn === "function") {
+      obj = fn(context);
+    } else {
+      obj = fn;
+    }
+
+    if ((typeof obj === "undefined" ? "undefined" : (0, _typeof3.default)(obj)) === "object") {
+      var _plugin = new _plugin3.default(obj, alias);
+      OptionManager.memoisedPlugins.push({
+        container: fn,
+        plugin: _plugin
+      });
+      return _plugin;
+    } else {
+      throw new TypeError(messages.get("pluginNotObject", loc, i, typeof obj === "undefined" ? "undefined" : (0, _typeof3.default)(obj)) + loc + i);
+    }
+  };
+
+  OptionManager.createBareOptions = function createBareOptions() {
+    var opts = {};
+
+    for (var _key in _config3.default) {
+      var opt = _config3.default[_key];
+      opts[_key] = (0, _clone2.default)(opt.default);
+    }
+
+    return opts;
+  };
+
+  OptionManager.normalisePlugin = function normalisePlugin(plugin, loc, i, alias) {
+    plugin = plugin.__esModule ? plugin.default : plugin;
+
+    if (!(plugin instanceof _plugin3.default)) {
+      if (typeof plugin === "function" || (typeof plugin === "undefined" ? "undefined" : (0, _typeof3.default)(plugin)) === "object") {
+        plugin = OptionManager.memoisePluginContainer(plugin, loc, i, alias);
+      } else {
+        throw new TypeError(messages.get("pluginNotFunction", loc, i, typeof plugin === "undefined" ? "undefined" : (0, _typeof3.default)(plugin)));
+      }
+    }
+
+    plugin.init(loc, i);
+
+    return plugin;
+  };
+
+  OptionManager.normalisePlugins = function normalisePlugins(loc, dirname, plugins) {
+    return plugins.map(function (val, i) {
+      var plugin = void 0,
+          options = void 0;
+
+      if (!val) {
+        throw new TypeError("Falsy value found in plugins");
+      }
+
+      if (Array.isArray(val)) {
+        plugin = val[0];
+        options = val[1];
+      } else {
+        plugin = val;
+      }
+
+      var alias = typeof plugin === "string" ? plugin : loc + "$" + i;
+
+      if (typeof plugin === "string") {
+        var pluginLoc = (0, _resolvePlugin2.default)(plugin, dirname);
+        if (pluginLoc) {
+          plugin = require(pluginLoc);
+        } else {
+          throw new ReferenceError(messages.get("pluginUnknown", plugin, loc, i, dirname));
+        }
+      }
+
+      plugin = OptionManager.normalisePlugin(plugin, loc, i, alias);
+
+      return [plugin, options];
+    });
+  };
+
+  OptionManager.prototype.mergeOptions = function mergeOptions(_ref2) {
+    var _this = this;
+
+    var rawOpts = _ref2.options,
+        extendingOpts = _ref2.extending,
+        alias = _ref2.alias,
+        loc = _ref2.loc,
+        dirname = _ref2.dirname;
+
+    alias = alias || "foreign";
+    if (!rawOpts) return;
+
+    if ((typeof rawOpts === "undefined" ? "undefined" : (0, _typeof3.default)(rawOpts)) !== "object" || Array.isArray(rawOpts)) {
+      this.log.error("Invalid options type for " + alias, TypeError);
+    }
+
+    var opts = (0, _cloneDeepWith2.default)(rawOpts, function (val) {
+      if (val instanceof _plugin3.default) {
+        return val;
+      }
+    });
+
+    dirname = dirname || process.cwd();
+    loc = loc || alias;
+
+    for (var _key2 in opts) {
+      var option = _config3.default[_key2];
+
+      if (!option && this.log) {
+        if (_removed2.default[_key2]) {
+          this.log.error("Using removed Babel 5 option: " + alias + "." + _key2 + " - " + _removed2.default[_key2].message, ReferenceError);
+        } else {
+          var unknownOptErr = "Unknown option: " + alias + "." + _key2 + ". Check out http://babeljs.io/docs/usage/options/ for more information about options.";
+          var presetConfigErr = "A common cause of this error is the presence of a configuration options object without the corresponding preset name. Example:\n\nInvalid:\n  `{ presets: [{option: value}] }`\nValid:\n  `{ presets: [['presetName', {option: value}]] }`\n\nFor more detailed information on preset configuration, please see http://babeljs.io/docs/plugins/#pluginpresets-options.";
+
+
+          this.log.error(unknownOptErr + "\n\n" + presetConfigErr, ReferenceError);
+        }
+      }
+    }
+
+    (0, _index.normaliseOptions)(opts);
+
+    if (opts.plugins) {
+      opts.plugins = OptionManager.normalisePlugins(loc, dirname, opts.plugins);
+    }
+
+    if (opts.presets) {
+      if (opts.passPerPreset) {
+        opts.presets = this.resolvePresets(opts.presets, dirname, function (preset, presetLoc) {
+          _this.mergeOptions({
+            options: preset,
+            extending: preset,
+            alias: presetLoc,
+            loc: presetLoc,
+            dirname: dirname
+          });
+        });
+      } else {
+        this.mergePresets(opts.presets, dirname);
+        delete opts.presets;
+      }
+    }
+
+    if (rawOpts === extendingOpts) {
+      (0, _assign2.default)(extendingOpts, opts);
+    } else {
+      (0, _merge2.default)(extendingOpts || this.options, opts);
+    }
+  };
+
+  OptionManager.prototype.mergePresets = function mergePresets(presets, dirname) {
+    var _this2 = this;
+
+    this.resolvePresets(presets, dirname, function (presetOpts, presetLoc) {
+      _this2.mergeOptions({
+        options: presetOpts,
+        alias: presetLoc,
+        loc: presetLoc,
+        dirname: _path2.default.dirname(presetLoc || "")
+      });
+    });
+  };
+
+  OptionManager.prototype.resolvePresets = function resolvePresets(presets, dirname, onResolve) {
+    return presets.map(function (val) {
+      var options = void 0;
+      if (Array.isArray(val)) {
+        if (val.length > 2) {
+          throw new Error("Unexpected extra options " + (0, _stringify2.default)(val.slice(2)) + " passed to preset.");
+        }
+
+        var _val = val;
+        val = _val[0];
+        options = _val[1];
+      }
+
+      var presetLoc = void 0;
+      try {
+        if (typeof val === "string") {
+          presetLoc = (0, _resolvePreset2.default)(val, dirname);
+
+          if (!presetLoc) {
+            throw new Error("Couldn't find preset " + (0, _stringify2.default)(val) + " relative to directory " + (0, _stringify2.default)(dirname));
+          }
+
+          val = require(presetLoc);
+        }
+
+        if ((typeof val === "undefined" ? "undefined" : (0, _typeof3.default)(val)) === "object" && val.__esModule) {
+          if (val.default) {
+            val = val.default;
+          } else {
+            var _val2 = val,
+                __esModule = _val2.__esModule,
+                rest = (0, _objectWithoutProperties3.default)(_val2, ["__esModule"]);
+
+            val = rest;
+          }
+        }
+
+        if ((typeof val === "undefined" ? "undefined" : (0, _typeof3.default)(val)) === "object" && val.buildPreset) val = val.buildPreset;
+
+        if (typeof val !== "function" && options !== undefined) {
+          throw new Error("Options " + (0, _stringify2.default)(options) + " passed to " + (presetLoc || "a preset") + " which does not accept options.");
+        }
+
+        if (typeof val === "function") val = val(context, options, { dirname: dirname });
+
+        if ((typeof val === "undefined" ? "undefined" : (0, _typeof3.default)(val)) !== "object") {
+          throw new Error("Unsupported preset format: " + val + ".");
+        }
+
+        onResolve && onResolve(val, presetLoc);
+      } catch (e) {
+        if (presetLoc) {
+          e.message += " (While processing preset: " + (0, _stringify2.default)(presetLoc) + ")";
+        }
+        throw e;
+      }
+      return val;
+    });
+  };
+
+  OptionManager.prototype.normaliseOptions = function normaliseOptions() {
+    var opts = this.options;
+
+    for (var _key3 in _config3.default) {
+      var option = _config3.default[_key3];
+      var val = opts[_key3];
+
+      if (!val && option.optional) continue;
+
+      if (option.alias) {
+        opts[option.alias] = opts[option.alias] || val;
+      } else {
+        opts[_key3] = val;
+      }
+    }
+  };
+
+  OptionManager.prototype.init = function init() {
+    var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+    for (var _iterator2 = (0, _buildConfigChain2.default)(opts, this.log), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref3;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref3 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref3 = _i2.value;
+      }
+
+      var _config = _ref3;
+
+      this.mergeOptions(_config);
+    }
+
+    this.normaliseOptions(opts);
+
+    return this.options;
+  };
+
+  return OptionManager;
+}();
+
+exports.default = OptionManager;
+
+
+OptionManager.memoisedPlugins = [];
+module.exports = exports["default"];
+}).call(this,require('_process'))
+},{"../../../api/node":6,"../../../helpers/merge":9,"../../../helpers/resolve-plugin":12,"../../../helpers/resolve-preset":13,"../../plugin":30,"./build-config-chain":20,"./config":21,"./index":22,"./removed":25,"_process":525,"babel-messages":61,"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/json/stringify":96,"babel-runtime/core-js/object/assign":99,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/objectWithoutProperties":111,"babel-runtime/helpers/typeof":113,"lodash/clone":466,"lodash/cloneDeepWith":468,"path":522}],24:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.filename = undefined;
+exports.boolean = boolean;
+exports.booleanString = booleanString;
+exports.list = list;
+
+var _slash = require("slash");
+
+var _slash2 = _interopRequireDefault(_slash);
+
+var _util = require("../../../util");
+
+var util = _interopRequireWildcard(_util);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var filename = exports.filename = _slash2.default;
+
+function boolean(val) {
+  return !!val;
+}
+
+function booleanString(val) {
+  return util.booleanify(val);
+}
+
+function list(val) {
+  return util.list(val);
+}
+},{"../../../util":31,"slash":541}],25:[function(require,module,exports){
+"use strict";
+
+module.exports = {
+  "auxiliaryComment": {
+    "message": "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`"
+  },
+  "blacklist": {
+    "message": "Put the specific transforms you want in the `plugins` option"
+  },
+  "breakConfig": {
+    "message": "This is not a necessary option in Babel 6"
+  },
+  "experimental": {
+    "message": "Put the specific transforms you want in the `plugins` option"
+  },
+  "externalHelpers": {
+    "message": "Use the `external-helpers` plugin instead. Check out http://babeljs.io/docs/plugins/external-helpers/"
+  },
+  "extra": {
+    "message": ""
+  },
+  "jsxPragma": {
+    "message": "use the `pragma` option in the `react-jsx` plugin . Check out http://babeljs.io/docs/plugins/transform-react-jsx/"
+  },
+
+  "loose": {
+    "message": "Specify the `loose` option for the relevant plugin you are using or use a preset that sets the option."
+  },
+  "metadataUsedHelpers": {
+    "message": "Not required anymore as this is enabled by default"
+  },
+  "modules": {
+    "message": "Use the corresponding module transform plugin in the `plugins` option. Check out http://babeljs.io/docs/plugins/#modules"
+  },
+  "nonStandard": {
+    "message": "Use the `react-jsx` and `flow-strip-types` plugins to support JSX and Flow. Also check out the react preset http://babeljs.io/docs/plugins/preset-react/"
+  },
+  "optional": {
+    "message": "Put the specific transforms you want in the `plugins` option"
+  },
+  "sourceMapName": {
+    "message": "Use the `sourceMapTarget` option"
+  },
+  "stage": {
+    "message": "Check out the corresponding stage-x presets http://babeljs.io/docs/plugins/#presets"
+  },
+  "whitelist": {
+    "message": "Put the specific transforms you want in the `plugins` option"
+  }
+};
+},{}],26:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _plugin = require("../plugin");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+var _sortBy = require("lodash/sortBy");
+
+var _sortBy2 = _interopRequireDefault(_sortBy);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = new _plugin2.default({
+
+  name: "internal.blockHoist",
+
+  visitor: {
+    Block: {
+      exit: function exit(_ref) {
+        var node = _ref.node;
+
+        var hasChange = false;
+        for (var i = 0; i < node.body.length; i++) {
+          var bodyNode = node.body[i];
+          if (bodyNode && bodyNode._blockHoist != null) {
+            hasChange = true;
+            break;
+          }
+        }
+        if (!hasChange) return;
+
+        node.body = (0, _sortBy2.default)(node.body, function (bodyNode) {
+          var priority = bodyNode && bodyNode._blockHoist;
+          if (priority == null) priority = 1;
+          if (priority === true) priority = 2;
+
+          return -1 * priority;
+        });
+      }
+    }
+  }
+});
+module.exports = exports["default"];
+},{"../plugin":30,"lodash/sortBy":508}],27:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+var _plugin = require("../plugin");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var SUPER_THIS_BOUND = (0, _symbol2.default)("super this bound");
+
+var superVisitor = {
+  CallExpression: function CallExpression(path) {
+    if (!path.get("callee").isSuper()) return;
+
+    var node = path.node;
+
+    if (node[SUPER_THIS_BOUND]) return;
+    node[SUPER_THIS_BOUND] = true;
+
+    path.replaceWith(t.assignmentExpression("=", this.id, node));
+  }
+};
+
+exports.default = new _plugin2.default({
+  name: "internal.shadowFunctions",
+
+  visitor: {
+    ThisExpression: function ThisExpression(path) {
+      remap(path, "this");
+    },
+    ReferencedIdentifier: function ReferencedIdentifier(path) {
+      if (path.node.name === "arguments") {
+        remap(path, "arguments");
+      }
+    }
+  }
+});
+
+
+function shouldShadow(path, shadowPath) {
+  if (path.is("_forceShadow")) {
+    return true;
+  } else {
+    return shadowPath;
+  }
+}
+
+function remap(path, key) {
+  var shadowPath = path.inShadow(key);
+  if (!shouldShadow(path, shadowPath)) return;
+
+  var shadowFunction = path.node._shadowedFunctionLiteral;
+
+  var currentFunction = void 0;
+  var passedShadowFunction = false;
+
+  var fnPath = path.find(function (innerPath) {
+    if (innerPath.parentPath && innerPath.parentPath.isClassProperty() && innerPath.key === "value") {
+      return true;
+    }
+    if (path === innerPath) return false;
+    if (innerPath.isProgram() || innerPath.isFunction()) {
+      currentFunction = currentFunction || innerPath;
+    }
+
+    if (innerPath.isProgram()) {
+      passedShadowFunction = true;
+
+      return true;
+    } else if (innerPath.isFunction() && !innerPath.isArrowFunctionExpression()) {
+      if (shadowFunction) {
+        if (innerPath === shadowFunction || innerPath.node === shadowFunction.node) return true;
+      } else {
+        if (!innerPath.is("shadow")) return true;
+      }
+
+      passedShadowFunction = true;
+      return false;
+    }
+
+    return false;
+  });
+
+  if (shadowFunction && fnPath.isProgram() && !shadowFunction.isProgram()) {
+    fnPath = path.findParent(function (p) {
+      return p.isProgram() || p.isFunction();
+    });
+  }
+
+  if (fnPath === currentFunction) return;
+
+  if (!passedShadowFunction) return;
+
+  var cached = fnPath.getData(key);
+  if (cached) return path.replaceWith(cached);
+
+  var id = path.scope.generateUidIdentifier(key);
+
+  fnPath.setData(key, id);
+
+  var classPath = fnPath.findParent(function (p) {
+    return p.isClass();
+  });
+  var hasSuperClass = !!(classPath && classPath.node && classPath.node.superClass);
+
+  if (key === "this" && fnPath.isMethod({ kind: "constructor" }) && hasSuperClass) {
+    fnPath.scope.push({ id: id });
+
+    fnPath.traverse(superVisitor, { id: id });
+  } else {
+    var init = key === "this" ? t.thisExpression() : t.identifier(key);
+
+    if (shadowFunction) init._shadowedFunctionLiteral = shadowFunction;
+
+    fnPath.scope.push({ id: id, init: init });
+  }
+
+  return path.replaceWith(id);
+}
+module.exports = exports["default"];
+},{"../plugin":30,"babel-runtime/core-js/symbol":104,"babel-types":151}],28:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _normalizeAst = require("../helpers/normalize-ast");
+
+var _normalizeAst2 = _interopRequireDefault(_normalizeAst);
+
+var _plugin = require("./plugin");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+var _file = require("./file");
+
+var _file2 = _interopRequireDefault(_file);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var Pipeline = function () {
+  function Pipeline() {
+    (0, _classCallCheck3.default)(this, Pipeline);
+  }
+
+  Pipeline.prototype.lint = function lint(code) {
+    var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+    opts.code = false;
+    opts.mode = "lint";
+    return this.transform(code, opts);
+  };
+
+  Pipeline.prototype.pretransform = function pretransform(code, opts) {
+    var file = new _file2.default(opts, this);
+    return file.wrap(code, function () {
+      file.addCode(code);
+      file.parseCode(code);
+      return file;
+    });
+  };
+
+  Pipeline.prototype.transform = function transform(code, opts) {
+    var file = new _file2.default(opts, this);
+    return file.wrap(code, function () {
+      file.addCode(code);
+      file.parseCode(code);
+      return file.transform();
+    });
+  };
+
+  Pipeline.prototype.analyse = function analyse(code) {
+    var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+    var visitor = arguments[2];
+
+    opts.code = false;
+    if (visitor) {
+      opts.plugins = opts.plugins || [];
+      opts.plugins.push(new _plugin2.default({ visitor: visitor }));
+    }
+    return this.transform(code, opts).metadata;
+  };
+
+  Pipeline.prototype.transformFromAst = function transformFromAst(ast, code, opts) {
+    ast = (0, _normalizeAst2.default)(ast);
+
+    var file = new _file2.default(opts, this);
+    return file.wrap(code, function () {
+      file.addCode(code);
+      file.addAst(ast);
+      return file.transform();
+    });
+  };
+
+  return Pipeline;
+}();
+
+exports.default = Pipeline;
+module.exports = exports["default"];
+},{"../helpers/normalize-ast":10,"./file":17,"./plugin":30,"babel-runtime/helpers/classCallCheck":109}],29:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require("babel-runtime/helpers/inherits");
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _store = require("../store");
+
+var _store2 = _interopRequireDefault(_store);
+
+var _file5 = require("./file");
+
+var _file6 = _interopRequireDefault(_file5);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var PluginPass = function (_Store) {
+  (0, _inherits3.default)(PluginPass, _Store);
+
+  function PluginPass(file, plugin) {
+    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+    (0, _classCallCheck3.default)(this, PluginPass);
+
+    var _this = (0, _possibleConstructorReturn3.default)(this, _Store.call(this));
+
+    _this.plugin = plugin;
+    _this.key = plugin.key;
+    _this.file = file;
+    _this.opts = options;
+    return _this;
+  }
+
+  PluginPass.prototype.addHelper = function addHelper() {
+    var _file;
+
+    return (_file = this.file).addHelper.apply(_file, arguments);
+  };
+
+  PluginPass.prototype.addImport = function addImport() {
+    var _file2;
+
+    return (_file2 = this.file).addImport.apply(_file2, arguments);
+  };
+
+  PluginPass.prototype.getModuleName = function getModuleName() {
+    var _file3;
+
+    return (_file3 = this.file).getModuleName.apply(_file3, arguments);
+  };
+
+  PluginPass.prototype.buildCodeFrameError = function buildCodeFrameError() {
+    var _file4;
+
+    return (_file4 = this.file).buildCodeFrameError.apply(_file4, arguments);
+  };
+
+  return PluginPass;
+}(_store2.default);
+
+exports.default = PluginPass;
+module.exports = exports["default"];
+},{"../store":15,"./file":17,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/inherits":110,"babel-runtime/helpers/possibleConstructorReturn":112}],30:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require("babel-runtime/helpers/inherits");
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _optionManager = require("./file/options/option-manager");
+
+var _optionManager2 = _interopRequireDefault(_optionManager);
+
+var _babelMessages = require("babel-messages");
+
+var messages = _interopRequireWildcard(_babelMessages);
+
+var _store = require("../store");
+
+var _store2 = _interopRequireDefault(_store);
+
+var _babelTraverse = require("babel-traverse");
+
+var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
+
+var _assign = require("lodash/assign");
+
+var _assign2 = _interopRequireDefault(_assign);
+
+var _clone = require("lodash/clone");
+
+var _clone2 = _interopRequireDefault(_clone);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var GLOBAL_VISITOR_PROPS = ["enter", "exit"];
+
+var Plugin = function (_Store) {
+  (0, _inherits3.default)(Plugin, _Store);
+
+  function Plugin(plugin, key) {
+    (0, _classCallCheck3.default)(this, Plugin);
+
+    var _this = (0, _possibleConstructorReturn3.default)(this, _Store.call(this));
+
+    _this.initialized = false;
+    _this.raw = (0, _assign2.default)({}, plugin);
+    _this.key = _this.take("name") || key;
+
+    _this.manipulateOptions = _this.take("manipulateOptions");
+    _this.post = _this.take("post");
+    _this.pre = _this.take("pre");
+    _this.visitor = _this.normaliseVisitor((0, _clone2.default)(_this.take("visitor")) || {});
+    return _this;
+  }
+
+  Plugin.prototype.take = function take(key) {
+    var val = this.raw[key];
+    delete this.raw[key];
+    return val;
+  };
+
+  Plugin.prototype.chain = function chain(target, key) {
+    if (!target[key]) return this[key];
+    if (!this[key]) return target[key];
+
+    var fns = [target[key], this[key]];
+
+    return function () {
+      var val = void 0;
+
+      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+        args[_key] = arguments[_key];
+      }
+
+      for (var _iterator = fns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+        var _ref;
+
+        if (_isArray) {
+          if (_i >= _iterator.length) break;
+          _ref = _iterator[_i++];
+        } else {
+          _i = _iterator.next();
+          if (_i.done) break;
+          _ref = _i.value;
+        }
+
+        var fn = _ref;
+
+        if (fn) {
+          var ret = fn.apply(this, args);
+          if (ret != null) val = ret;
+        }
+      }
+      return val;
+    };
+  };
+
+  Plugin.prototype.maybeInherit = function maybeInherit(loc) {
+    var inherits = this.take("inherits");
+    if (!inherits) return;
+
+    inherits = _optionManager2.default.normalisePlugin(inherits, loc, "inherits");
+
+    this.manipulateOptions = this.chain(inherits, "manipulateOptions");
+    this.post = this.chain(inherits, "post");
+    this.pre = this.chain(inherits, "pre");
+    this.visitor = _babelTraverse2.default.visitors.merge([inherits.visitor, this.visitor]);
+  };
+
+  Plugin.prototype.init = function init(loc, i) {
+    if (this.initialized) return;
+    this.initialized = true;
+
+    this.maybeInherit(loc);
+
+    for (var key in this.raw) {
+      throw new Error(messages.get("pluginInvalidProperty", loc, i, key));
+    }
+  };
+
+  Plugin.prototype.normaliseVisitor = function normaliseVisitor(visitor) {
+    for (var _iterator2 = GLOBAL_VISITOR_PROPS, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref2;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref2 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref2 = _i2.value;
+      }
+
+      var key = _ref2;
+
+      if (visitor[key]) {
+        throw new Error("Plugins aren't allowed to specify catch-all enter/exit handlers. " + "Please target individual nodes.");
+      }
+    }
+
+    _babelTraverse2.default.explode(visitor);
+    return visitor;
+  };
+
+  return Plugin;
+}(_store2.default);
+
+exports.default = Plugin;
+module.exports = exports["default"];
+},{"../store":15,"./file/options/option-manager":23,"babel-messages":61,"babel-runtime/core-js/get-iterator":95,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/inherits":110,"babel-runtime/helpers/possibleConstructorReturn":112,"babel-traverse":118,"lodash/assign":463,"lodash/clone":466}],31:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.inspect = exports.inherits = undefined;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _util = require("util");
+
+Object.defineProperty(exports, "inherits", {
+  enumerable: true,
+  get: function get() {
+    return _util.inherits;
+  }
+});
+Object.defineProperty(exports, "inspect", {
+  enumerable: true,
+  get: function get() {
+    return _util.inspect;
+  }
+});
+exports.canCompile = canCompile;
+exports.list = list;
+exports.regexify = regexify;
+exports.arrayify = arrayify;
+exports.booleanify = booleanify;
+exports.shouldIgnore = shouldIgnore;
+
+var _escapeRegExp = require("lodash/escapeRegExp");
+
+var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp);
+
+var _startsWith = require("lodash/startsWith");
+
+var _startsWith2 = _interopRequireDefault(_startsWith);
+
+var _minimatch = require("minimatch");
+
+var _minimatch2 = _interopRequireDefault(_minimatch);
+
+var _includes = require("lodash/includes");
+
+var _includes2 = _interopRequireDefault(_includes);
+
+var _isRegExp = require("lodash/isRegExp");
+
+var _isRegExp2 = _interopRequireDefault(_isRegExp);
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+var _slash = require("slash");
+
+var _slash2 = _interopRequireDefault(_slash);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function canCompile(filename, altExts) {
+  var exts = altExts || canCompile.EXTENSIONS;
+  var ext = _path2.default.extname(filename);
+  return (0, _includes2.default)(exts, ext);
+}
+
+canCompile.EXTENSIONS = [".js", ".jsx", ".es6", ".es"];
+
+function list(val) {
+  if (!val) {
+    return [];
+  } else if (Array.isArray(val)) {
+    return val;
+  } else if (typeof val === "string") {
+    return val.split(",");
+  } else {
+    return [val];
+  }
+}
+
+function regexify(val) {
+  if (!val) {
+    return new RegExp(/.^/);
+  }
+
+  if (Array.isArray(val)) {
+    val = new RegExp(val.map(_escapeRegExp2.default).join("|"), "i");
+  }
+
+  if (typeof val === "string") {
+    val = (0, _slash2.default)(val);
+
+    if ((0, _startsWith2.default)(val, "./") || (0, _startsWith2.default)(val, "*/")) val = val.slice(2);
+    if ((0, _startsWith2.default)(val, "**/")) val = val.slice(3);
+
+    var regex = _minimatch2.default.makeRe(val, { nocase: true });
+    return new RegExp(regex.source.slice(1, -1), "i");
+  }
+
+  if ((0, _isRegExp2.default)(val)) {
+    return val;
+  }
+
+  throw new TypeError("illegal type for regexify");
+}
+
+function arrayify(val, mapFn) {
+  if (!val) return [];
+  if (typeof val === "boolean") return arrayify([val], mapFn);
+  if (typeof val === "string") return arrayify(list(val), mapFn);
+
+  if (Array.isArray(val)) {
+    if (mapFn) val = val.map(mapFn);
+    return val;
+  }
+
+  return [val];
+}
+
+function booleanify(val) {
+  if (val === "true" || val == 1) {
+    return true;
+  }
+
+  if (val === "false" || val == 0 || !val) {
+    return false;
+  }
+
+  return val;
+}
+
+function shouldIgnore(filename) {
+  var ignore = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
+  var only = arguments[2];
+
+  filename = filename.replace(/\\/g, "/");
+
+  if (only) {
+    for (var _iterator = only, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var pattern = _ref;
+
+      if (_shouldIgnore(pattern, filename)) return false;
+    }
+    return true;
+  } else if (ignore.length) {
+    for (var _iterator2 = ignore, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref2;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref2 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref2 = _i2.value;
+      }
+
+      var _pattern = _ref2;
+
+      if (_shouldIgnore(_pattern, filename)) return true;
+    }
+  }
+
+  return false;
+}
+
+function _shouldIgnore(pattern, filename) {
+  if (typeof pattern === "function") {
+    return pattern(filename);
+  } else {
+    return pattern.test(filename);
+  }
+}
+},{"babel-runtime/core-js/get-iterator":95,"lodash/escapeRegExp":472,"lodash/includes":482,"lodash/isRegExp":494,"lodash/startsWith":509,"minimatch":519,"path":522,"slash":541,"util":560}],32:[function(require,module,exports){
+module.exports={
+  "_from": "babel-core@^6.22.1",
+  "_id": "babel-core@6.26.0",
+  "_inBundle": false,
+  "_integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
+  "_location": "/babel-core",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "babel-core@^6.22.1",
+    "name": "babel-core",
+    "escapedName": "babel-core",
+    "rawSpec": "^6.22.1",
+    "saveSpec": null,
+    "fetchSpec": "^6.22.1"
+  },
+  "_requiredBy": [
+    "#DEV:/",
+    "/babel-register",
+    "/babelify",
+    "/karma-babel-preprocessor"
+  ],
+  "_resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
+  "_shasum": "af32f78b31a6fcef119c87b0fd8d9753f03a0bb8",
+  "_spec": "babel-core@^6.22.1",
+  "_where": "/Users/juanjodiaz/Documents/code/OSS libs/noVNC",
+  "author": {
+    "name": "Sebastian McKenzie",
+    "email": "sebmck@gmail.com"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "babel-code-frame": "^6.26.0",
+    "babel-generator": "^6.26.0",
+    "babel-helpers": "^6.24.1",
+    "babel-messages": "^6.23.0",
+    "babel-register": "^6.26.0",
+    "babel-runtime": "^6.26.0",
+    "babel-template": "^6.26.0",
+    "babel-traverse": "^6.26.0",
+    "babel-types": "^6.26.0",
+    "babylon": "^6.18.0",
+    "convert-source-map": "^1.5.0",
+    "debug": "^2.6.8",
+    "json5": "^0.5.1",
+    "lodash": "^4.17.4",
+    "minimatch": "^3.0.4",
+    "path-is-absolute": "^1.0.1",
+    "private": "^0.1.7",
+    "slash": "^1.0.0",
+    "source-map": "^0.5.6"
+  },
+  "deprecated": false,
+  "description": "Babel compiler core.",
+  "devDependencies": {
+    "babel-helper-fixtures": "^6.26.0",
+    "babel-helper-transform-fixture-test-runner": "^6.26.0",
+    "babel-polyfill": "^6.26.0"
+  },
+  "homepage": "https://babeljs.io/",
+  "keywords": [
+    "6to5",
+    "babel",
+    "classes",
+    "const",
+    "es6",
+    "harmony",
+    "let",
+    "modules",
+    "transpile",
+    "transpiler",
+    "var",
+    "babel-core",
+    "compiler"
+  ],
+  "license": "MIT",
+  "name": "babel-core",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/babel/babel/tree/master/packages/babel-core"
+  },
+  "scripts": {
+    "bench": "make bench",
+    "test": "make test"
+  },
+  "version": "6.26.0"
+}
+
+},{}],33:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _trimRight = require("trim-right");
+
+var _trimRight2 = _interopRequireDefault(_trimRight);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var SPACES_RE = /^[ \t]+$/;
+
+var Buffer = function () {
+  function Buffer(map) {
+    (0, _classCallCheck3.default)(this, Buffer);
+    this._map = null;
+    this._buf = [];
+    this._last = "";
+    this._queue = [];
+    this._position = {
+      line: 1,
+      column: 0
+    };
+    this._sourcePosition = {
+      identifierName: null,
+      line: null,
+      column: null,
+      filename: null
+    };
+
+    this._map = map;
+  }
+
+  Buffer.prototype.get = function get() {
+    this._flush();
+
+    var map = this._map;
+    var result = {
+      code: (0, _trimRight2.default)(this._buf.join("")),
+      map: null,
+      rawMappings: map && map.getRawMappings()
+    };
+
+    if (map) {
+      Object.defineProperty(result, "map", {
+        configurable: true,
+        enumerable: true,
+        get: function get() {
+          return this.map = map.get();
+        },
+        set: function set(value) {
+          Object.defineProperty(this, "map", { value: value, writable: true });
+        }
+      });
+    }
+
+    return result;
+  };
+
+  Buffer.prototype.append = function append(str) {
+    this._flush();
+    var _sourcePosition = this._sourcePosition,
+        line = _sourcePosition.line,
+        column = _sourcePosition.column,
+        filename = _sourcePosition.filename,
+        identifierName = _sourcePosition.identifierName;
+
+    this._append(str, line, column, identifierName, filename);
+  };
+
+  Buffer.prototype.queue = function queue(str) {
+    if (str === "\n") while (this._queue.length > 0 && SPACES_RE.test(this._queue[0][0])) {
+      this._queue.shift();
+    }var _sourcePosition2 = this._sourcePosition,
+        line = _sourcePosition2.line,
+        column = _sourcePosition2.column,
+        filename = _sourcePosition2.filename,
+        identifierName = _sourcePosition2.identifierName;
+
+    this._queue.unshift([str, line, column, identifierName, filename]);
+  };
+
+  Buffer.prototype._flush = function _flush() {
+    var item = void 0;
+    while (item = this._queue.pop()) {
+      this._append.apply(this, item);
+    }
+  };
+
+  Buffer.prototype._append = function _append(str, line, column, identifierName, filename) {
+    if (this._map && str[0] !== "\n") {
+      this._map.mark(this._position.line, this._position.column, line, column, identifierName, filename);
+    }
+
+    this._buf.push(str);
+    this._last = str[str.length - 1];
+
+    for (var i = 0; i < str.length; i++) {
+      if (str[i] === "\n") {
+        this._position.line++;
+        this._position.column = 0;
+      } else {
+        this._position.column++;
+      }
+    }
+  };
+
+  Buffer.prototype.removeTrailingNewline = function removeTrailingNewline() {
+    if (this._queue.length > 0 && this._queue[0][0] === "\n") this._queue.shift();
+  };
+
+  Buffer.prototype.removeLastSemicolon = function removeLastSemicolon() {
+    if (this._queue.length > 0 && this._queue[0][0] === ";") this._queue.shift();
+  };
+
+  Buffer.prototype.endsWith = function endsWith(suffix) {
+    if (suffix.length === 1) {
+      var last = void 0;
+      if (this._queue.length > 0) {
+        var str = this._queue[0][0];
+        last = str[str.length - 1];
+      } else {
+        last = this._last;
+      }
+
+      return last === suffix;
+    }
+
+    var end = this._last + this._queue.reduce(function (acc, item) {
+      return item[0] + acc;
+    }, "");
+    if (suffix.length <= end.length) {
+      return end.slice(-suffix.length) === suffix;
+    }
+
+    return false;
+  };
+
+  Buffer.prototype.hasContent = function hasContent() {
+    return this._queue.length > 0 || !!this._last;
+  };
+
+  Buffer.prototype.source = function source(prop, loc) {
+    if (prop && !loc) return;
+
+    var pos = loc ? loc[prop] : null;
+
+    this._sourcePosition.identifierName = loc && loc.identifierName || null;
+    this._sourcePosition.line = pos ? pos.line : null;
+    this._sourcePosition.column = pos ? pos.column : null;
+    this._sourcePosition.filename = loc && loc.filename || null;
+  };
+
+  Buffer.prototype.withSource = function withSource(prop, loc, cb) {
+    if (!this._map) return cb();
+
+    var originalLine = this._sourcePosition.line;
+    var originalColumn = this._sourcePosition.column;
+    var originalFilename = this._sourcePosition.filename;
+    var originalIdentifierName = this._sourcePosition.identifierName;
+
+    this.source(prop, loc);
+
+    cb();
+
+    this._sourcePosition.line = originalLine;
+    this._sourcePosition.column = originalColumn;
+    this._sourcePosition.filename = originalFilename;
+    this._sourcePosition.identifierName = originalIdentifierName;
+  };
+
+  Buffer.prototype.getCurrentColumn = function getCurrentColumn() {
+    var extra = this._queue.reduce(function (acc, item) {
+      return item[0] + acc;
+    }, "");
+    var lastIndex = extra.lastIndexOf("\n");
+
+    return lastIndex === -1 ? this._position.column + extra.length : extra.length - 1 - lastIndex;
+  };
+
+  Buffer.prototype.getCurrentLine = function getCurrentLine() {
+    var extra = this._queue.reduce(function (acc, item) {
+      return item[0] + acc;
+    }, "");
+
+    var count = 0;
+    for (var i = 0; i < extra.length; i++) {
+      if (extra[i] === "\n") count++;
+    }
+
+    return this._position.line + count;
+  };
+
+  return Buffer;
+}();
+
+exports.default = Buffer;
+module.exports = exports["default"];
+},{"babel-runtime/helpers/classCallCheck":109,"trim-right":556}],34:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.File = File;
+exports.Program = Program;
+exports.BlockStatement = BlockStatement;
+exports.Noop = Noop;
+exports.Directive = Directive;
+
+var _types = require("./types");
+
+Object.defineProperty(exports, "DirectiveLiteral", {
+  enumerable: true,
+  get: function get() {
+    return _types.StringLiteral;
+  }
+});
+function File(node) {
+  this.print(node.program, node);
+}
+
+function Program(node) {
+  this.printInnerComments(node, false);
+
+  this.printSequence(node.directives, node);
+  if (node.directives && node.directives.length) this.newline();
+
+  this.printSequence(node.body, node);
+}
+
+function BlockStatement(node) {
+  this.token("{");
+  this.printInnerComments(node);
+
+  var hasDirectives = node.directives && node.directives.length;
+
+  if (node.body.length || hasDirectives) {
+    this.newline();
+
+    this.printSequence(node.directives, node, { indent: true });
+    if (hasDirectives) this.newline();
+
+    this.printSequence(node.body, node, { indent: true });
+    this.removeTrailingNewline();
+
+    this.source("end", node.loc);
+
+    if (!this.endsWith("\n")) this.newline();
+
+    this.rightBrace();
+  } else {
+    this.source("end", node.loc);
+    this.token("}");
+  }
+}
+
+function Noop() {}
+
+function Directive(node) {
+  this.print(node.value, node);
+  this.semicolon();
+}
+},{"./types":43}],35:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.ClassDeclaration = ClassDeclaration;
+exports.ClassBody = ClassBody;
+exports.ClassProperty = ClassProperty;
+exports.ClassMethod = ClassMethod;
+function ClassDeclaration(node) {
+  this.printJoin(node.decorators, node);
+  this.word("class");
+
+  if (node.id) {
+    this.space();
+    this.print(node.id, node);
+  }
+
+  this.print(node.typeParameters, node);
+
+  if (node.superClass) {
+    this.space();
+    this.word("extends");
+    this.space();
+    this.print(node.superClass, node);
+    this.print(node.superTypeParameters, node);
+  }
+
+  if (node.implements) {
+    this.space();
+    this.word("implements");
+    this.space();
+    this.printList(node.implements, node);
+  }
+
+  this.space();
+  this.print(node.body, node);
+}
+
+exports.ClassExpression = ClassDeclaration;
+function ClassBody(node) {
+  this.token("{");
+  this.printInnerComments(node);
+  if (node.body.length === 0) {
+    this.token("}");
+  } else {
+    this.newline();
+
+    this.indent();
+    this.printSequence(node.body, node);
+    this.dedent();
+
+    if (!this.endsWith("\n")) this.newline();
+
+    this.rightBrace();
+  }
+}
+
+function ClassProperty(node) {
+  this.printJoin(node.decorators, node);
+
+  if (node.static) {
+    this.word("static");
+    this.space();
+  }
+  if (node.computed) {
+    this.token("[");
+    this.print(node.key, node);
+    this.token("]");
+  } else {
+    this._variance(node);
+    this.print(node.key, node);
+  }
+  this.print(node.typeAnnotation, node);
+  if (node.value) {
+    this.space();
+    this.token("=");
+    this.space();
+    this.print(node.value, node);
+  }
+  this.semicolon();
+}
+
+function ClassMethod(node) {
+  this.printJoin(node.decorators, node);
+
+  if (node.static) {
+    this.word("static");
+    this.space();
+  }
+
+  if (node.kind === "constructorCall") {
+    this.word("call");
+    this.space();
+  }
+
+  this._method(node);
+}
+},{}],36:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.LogicalExpression = exports.BinaryExpression = exports.AwaitExpression = exports.YieldExpression = undefined;
+exports.UnaryExpression = UnaryExpression;
+exports.DoExpression = DoExpression;
+exports.ParenthesizedExpression = ParenthesizedExpression;
+exports.UpdateExpression = UpdateExpression;
+exports.ConditionalExpression = ConditionalExpression;
+exports.NewExpression = NewExpression;
+exports.SequenceExpression = SequenceExpression;
+exports.ThisExpression = ThisExpression;
+exports.Super = Super;
+exports.Decorator = Decorator;
+exports.CallExpression = CallExpression;
+exports.Import = Import;
+exports.EmptyStatement = EmptyStatement;
+exports.ExpressionStatement = ExpressionStatement;
+exports.AssignmentPattern = AssignmentPattern;
+exports.AssignmentExpression = AssignmentExpression;
+exports.BindExpression = BindExpression;
+exports.MemberExpression = MemberExpression;
+exports.MetaProperty = MetaProperty;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+var _node = require("../node");
+
+var n = _interopRequireWildcard(_node);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function UnaryExpression(node) {
+  if (node.operator === "void" || node.operator === "delete" || node.operator === "typeof") {
+    this.word(node.operator);
+    this.space();
+  } else {
+    this.token(node.operator);
+  }
+
+  this.print(node.argument, node);
+}
+
+function DoExpression(node) {
+  this.word("do");
+  this.space();
+  this.print(node.body, node);
+}
+
+function ParenthesizedExpression(node) {
+  this.token("(");
+  this.print(node.expression, node);
+  this.token(")");
+}
+
+function UpdateExpression(node) {
+  if (node.prefix) {
+    this.token(node.operator);
+    this.print(node.argument, node);
+  } else {
+    this.print(node.argument, node);
+    this.token(node.operator);
+  }
+}
+
+function ConditionalExpression(node) {
+  this.print(node.test, node);
+  this.space();
+  this.token("?");
+  this.space();
+  this.print(node.consequent, node);
+  this.space();
+  this.token(":");
+  this.space();
+  this.print(node.alternate, node);
+}
+
+function NewExpression(node, parent) {
+  this.word("new");
+  this.space();
+  this.print(node.callee, node);
+  if (node.arguments.length === 0 && this.format.minified && !t.isCallExpression(parent, { callee: node }) && !t.isMemberExpression(parent) && !t.isNewExpression(parent)) return;
+
+  this.token("(");
+  this.printList(node.arguments, node);
+  this.token(")");
+}
+
+function SequenceExpression(node) {
+  this.printList(node.expressions, node);
+}
+
+function ThisExpression() {
+  this.word("this");
+}
+
+function Super() {
+  this.word("super");
+}
+
+function Decorator(node) {
+  this.token("@");
+  this.print(node.expression, node);
+  this.newline();
+}
+
+function commaSeparatorNewline() {
+  this.token(",");
+  this.newline();
+
+  if (!this.endsWith("\n")) this.space();
+}
+
+function CallExpression(node) {
+  this.print(node.callee, node);
+
+  this.token("(");
+
+  var isPrettyCall = node._prettyCall;
+
+  var separator = void 0;
+  if (isPrettyCall) {
+    separator = commaSeparatorNewline;
+    this.newline();
+    this.indent();
+  }
+
+  this.printList(node.arguments, node, { separator: separator });
+
+  if (isPrettyCall) {
+    this.newline();
+    this.dedent();
+  }
+
+  this.token(")");
+}
+
+function Import() {
+  this.word("import");
+}
+
+function buildYieldAwait(keyword) {
+  return function (node) {
+    this.word(keyword);
+
+    if (node.delegate) {
+      this.token("*");
+    }
+
+    if (node.argument) {
+      this.space();
+      var terminatorState = this.startTerminatorless();
+      this.print(node.argument, node);
+      this.endTerminatorless(terminatorState);
+    }
+  };
+}
+
+var YieldExpression = exports.YieldExpression = buildYieldAwait("yield");
+var AwaitExpression = exports.AwaitExpression = buildYieldAwait("await");
+
+function EmptyStatement() {
+  this.semicolon(true);
+}
+
+function ExpressionStatement(node) {
+  this.print(node.expression, node);
+  this.semicolon();
+}
+
+function AssignmentPattern(node) {
+  this.print(node.left, node);
+  if (node.left.optional) this.token("?");
+  this.print(node.left.typeAnnotation, node);
+  this.space();
+  this.token("=");
+  this.space();
+  this.print(node.right, node);
+}
+
+function AssignmentExpression(node, parent) {
+  var parens = this.inForStatementInitCounter && node.operator === "in" && !n.needsParens(node, parent);
+
+  if (parens) {
+    this.token("(");
+  }
+
+  this.print(node.left, node);
+
+  this.space();
+  if (node.operator === "in" || node.operator === "instanceof") {
+    this.word(node.operator);
+  } else {
+    this.token(node.operator);
+  }
+  this.space();
+
+  this.print(node.right, node);
+
+  if (parens) {
+    this.token(")");
+  }
+}
+
+function BindExpression(node) {
+  this.print(node.object, node);
+  this.token("::");
+  this.print(node.callee, node);
+}
+
+exports.BinaryExpression = AssignmentExpression;
+exports.LogicalExpression = AssignmentExpression;
+function MemberExpression(node) {
+  this.print(node.object, node);
+
+  if (!node.computed && t.isMemberExpression(node.property)) {
+    throw new TypeError("Got a MemberExpression for MemberExpression property");
+  }
+
+  var computed = node.computed;
+  if (t.isLiteral(node.property) && typeof node.property.value === "number") {
+    computed = true;
+  }
+
+  if (computed) {
+    this.token("[");
+    this.print(node.property, node);
+    this.token("]");
+  } else {
+    this.token(".");
+    this.print(node.property, node);
+  }
+}
+
+function MetaProperty(node) {
+  this.print(node.meta, node);
+  this.token(".");
+  this.print(node.property, node);
+}
+},{"../node":45,"babel-types":151}],37:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.TypeParameterDeclaration = exports.StringLiteralTypeAnnotation = exports.NumericLiteralTypeAnnotation = exports.GenericTypeAnnotation = exports.ClassImplements = undefined;
+exports.AnyTypeAnnotation = AnyTypeAnnotation;
+exports.ArrayTypeAnnotation = ArrayTypeAnnotation;
+exports.BooleanTypeAnnotation = BooleanTypeAnnotation;
+exports.BooleanLiteralTypeAnnotation = BooleanLiteralTypeAnnotation;
+exports.NullLiteralTypeAnnotation = NullLiteralTypeAnnotation;
+exports.DeclareClass = DeclareClass;
+exports.DeclareFunction = DeclareFunction;
+exports.DeclareInterface = DeclareInterface;
+exports.DeclareModule = DeclareModule;
+exports.DeclareModuleExports = DeclareModuleExports;
+exports.DeclareTypeAlias = DeclareTypeAlias;
+exports.DeclareOpaqueType = DeclareOpaqueType;
+exports.DeclareVariable = DeclareVariable;
+exports.DeclareExportDeclaration = DeclareExportDeclaration;
+exports.ExistentialTypeParam = ExistentialTypeParam;
+exports.FunctionTypeAnnotation = FunctionTypeAnnotation;
+exports.FunctionTypeParam = FunctionTypeParam;
+exports.InterfaceExtends = InterfaceExtends;
+exports._interfaceish = _interfaceish;
+exports._variance = _variance;
+exports.InterfaceDeclaration = InterfaceDeclaration;
+exports.IntersectionTypeAnnotation = IntersectionTypeAnnotation;
+exports.MixedTypeAnnotation = MixedTypeAnnotation;
+exports.EmptyTypeAnnotation = EmptyTypeAnnotation;
+exports.NullableTypeAnnotation = NullableTypeAnnotation;
+
+var _types = require("./types");
+
+Object.defineProperty(exports, "NumericLiteralTypeAnnotation", {
+  enumerable: true,
+  get: function get() {
+    return _types.NumericLiteral;
+  }
+});
+Object.defineProperty(exports, "StringLiteralTypeAnnotation", {
+  enumerable: true,
+  get: function get() {
+    return _types.StringLiteral;
+  }
+});
+exports.NumberTypeAnnotation = NumberTypeAnnotation;
+exports.StringTypeAnnotation = StringTypeAnnotation;
+exports.ThisTypeAnnotation = ThisTypeAnnotation;
+exports.TupleTypeAnnotation = TupleTypeAnnotation;
+exports.TypeofTypeAnnotation = TypeofTypeAnnotation;
+exports.TypeAlias = TypeAlias;
+exports.OpaqueType = OpaqueType;
+exports.TypeAnnotation = TypeAnnotation;
+exports.TypeParameter = TypeParameter;
+exports.TypeParameterInstantiation = TypeParameterInstantiation;
+exports.ObjectTypeAnnotation = ObjectTypeAnnotation;
+exports.ObjectTypeCallProperty = ObjectTypeCallProperty;
+exports.ObjectTypeIndexer = ObjectTypeIndexer;
+exports.ObjectTypeProperty = ObjectTypeProperty;
+exports.ObjectTypeSpreadProperty = ObjectTypeSpreadProperty;
+exports.QualifiedTypeIdentifier = QualifiedTypeIdentifier;
+exports.UnionTypeAnnotation = UnionTypeAnnotation;
+exports.TypeCastExpression = TypeCastExpression;
+exports.VoidTypeAnnotation = VoidTypeAnnotation;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function AnyTypeAnnotation() {
+  this.word("any");
+}
+
+function ArrayTypeAnnotation(node) {
+  this.print(node.elementType, node);
+  this.token("[");
+  this.token("]");
+}
+
+function BooleanTypeAnnotation() {
+  this.word("boolean");
+}
+
+function BooleanLiteralTypeAnnotation(node) {
+  this.word(node.value ? "true" : "false");
+}
+
+function NullLiteralTypeAnnotation() {
+  this.word("null");
+}
+
+function DeclareClass(node, parent) {
+  if (!t.isDeclareExportDeclaration(parent)) {
+    this.word("declare");
+    this.space();
+  }
+  this.word("class");
+  this.space();
+  this._interfaceish(node);
+}
+
+function DeclareFunction(node, parent) {
+  if (!t.isDeclareExportDeclaration(parent)) {
+    this.word("declare");
+    this.space();
+  }
+  this.word("function");
+  this.space();
+  this.print(node.id, node);
+  this.print(node.id.typeAnnotation.typeAnnotation, node);
+  this.semicolon();
+}
+
+function DeclareInterface(node) {
+  this.word("declare");
+  this.space();
+  this.InterfaceDeclaration(node);
+}
+
+function DeclareModule(node) {
+  this.word("declare");
+  this.space();
+  this.word("module");
+  this.space();
+  this.print(node.id, node);
+  this.space();
+  this.print(node.body, node);
+}
+
+function DeclareModuleExports(node) {
+  this.word("declare");
+  this.space();
+  this.word("module");
+  this.token(".");
+  this.word("exports");
+  this.print(node.typeAnnotation, node);
+}
+
+function DeclareTypeAlias(node) {
+  this.word("declare");
+  this.space();
+  this.TypeAlias(node);
+}
+
+function DeclareOpaqueType(node, parent) {
+  if (!t.isDeclareExportDeclaration(parent)) {
+    this.word("declare");
+    this.space();
+  }
+  this.OpaqueType(node);
+}
+
+function DeclareVariable(node, parent) {
+  if (!t.isDeclareExportDeclaration(parent)) {
+    this.word("declare");
+    this.space();
+  }
+  this.word("var");
+  this.space();
+  this.print(node.id, node);
+  this.print(node.id.typeAnnotation, node);
+  this.semicolon();
+}
+
+function DeclareExportDeclaration(node) {
+  this.word("declare");
+  this.space();
+  this.word("export");
+  this.space();
+  if (node.default) {
+    this.word("default");
+    this.space();
+  }
+
+  FlowExportDeclaration.apply(this, arguments);
+}
+
+function FlowExportDeclaration(node) {
+  if (node.declaration) {
+    var declar = node.declaration;
+    this.print(declar, node);
+    if (!t.isStatement(declar)) this.semicolon();
+  } else {
+    this.token("{");
+    if (node.specifiers.length) {
+      this.space();
+      this.printList(node.specifiers, node);
+      this.space();
+    }
+    this.token("}");
+
+    if (node.source) {
+      this.space();
+      this.word("from");
+      this.space();
+      this.print(node.source, node);
+    }
+
+    this.semicolon();
+  }
+}
+
+function ExistentialTypeParam() {
+  this.token("*");
+}
+
+function FunctionTypeAnnotation(node, parent) {
+  this.print(node.typeParameters, node);
+  this.token("(");
+  this.printList(node.params, node);
+
+  if (node.rest) {
+    if (node.params.length) {
+      this.token(",");
+      this.space();
+    }
+    this.token("...");
+    this.print(node.rest, node);
+  }
+
+  this.token(")");
+
+  if (parent.type === "ObjectTypeCallProperty" || parent.type === "DeclareFunction") {
+    this.token(":");
+  } else {
+    this.space();
+    this.token("=>");
+  }
+
+  this.space();
+  this.print(node.returnType, node);
+}
+
+function FunctionTypeParam(node) {
+  this.print(node.name, node);
+  if (node.optional) this.token("?");
+  this.token(":");
+  this.space();
+  this.print(node.typeAnnotation, node);
+}
+
+function InterfaceExtends(node) {
+  this.print(node.id, node);
+  this.print(node.typeParameters, node);
+}
+
+exports.ClassImplements = InterfaceExtends;
+exports.GenericTypeAnnotation = InterfaceExtends;
+function _interfaceish(node) {
+  this.print(node.id, node);
+  this.print(node.typeParameters, node);
+  if (node.extends.length) {
+    this.space();
+    this.word("extends");
+    this.space();
+    this.printList(node.extends, node);
+  }
+  if (node.mixins && node.mixins.length) {
+    this.space();
+    this.word("mixins");
+    this.space();
+    this.printList(node.mixins, node);
+  }
+  this.space();
+  this.print(node.body, node);
+}
+
+function _variance(node) {
+  if (node.variance === "plus") {
+    this.token("+");
+  } else if (node.variance === "minus") {
+    this.token("-");
+  }
+}
+
+function InterfaceDeclaration(node) {
+  this.word("interface");
+  this.space();
+  this._interfaceish(node);
+}
+
+function andSeparator() {
+  this.space();
+  this.token("&");
+  this.space();
+}
+
+function IntersectionTypeAnnotation(node) {
+  this.printJoin(node.types, node, { separator: andSeparator });
+}
+
+function MixedTypeAnnotation() {
+  this.word("mixed");
+}
+
+function EmptyTypeAnnotation() {
+  this.word("empty");
+}
+
+function NullableTypeAnnotation(node) {
+  this.token("?");
+  this.print(node.typeAnnotation, node);
+}
+
+function NumberTypeAnnotation() {
+  this.word("number");
+}
+
+function StringTypeAnnotation() {
+  this.word("string");
+}
+
+function ThisTypeAnnotation() {
+  this.word("this");
+}
+
+function TupleTypeAnnotation(node) {
+  this.token("[");
+  this.printList(node.types, node);
+  this.token("]");
+}
+
+function TypeofTypeAnnotation(node) {
+  this.word("typeof");
+  this.space();
+  this.print(node.argument, node);
+}
+
+function TypeAlias(node) {
+  this.word("type");
+  this.space();
+  this.print(node.id, node);
+  this.print(node.typeParameters, node);
+  this.space();
+  this.token("=");
+  this.space();
+  this.print(node.right, node);
+  this.semicolon();
+}
+function OpaqueType(node) {
+  this.word("opaque");
+  this.space();
+  this.word("type");
+  this.space();
+  this.print(node.id, node);
+  this.print(node.typeParameters, node);
+  if (node.supertype) {
+    this.token(":");
+    this.space();
+    this.print(node.supertype, node);
+  }
+  if (node.impltype) {
+    this.space();
+    this.token("=");
+    this.space();
+    this.print(node.impltype, node);
+  }
+  this.semicolon();
+}
+
+function TypeAnnotation(node) {
+  this.token(":");
+  this.space();
+  if (node.optional) this.token("?");
+  this.print(node.typeAnnotation, node);
+}
+
+function TypeParameter(node) {
+  this._variance(node);
+
+  this.word(node.name);
+
+  if (node.bound) {
+    this.print(node.bound, node);
+  }
+
+  if (node.default) {
+    this.space();
+    this.token("=");
+    this.space();
+    this.print(node.default, node);
+  }
+}
+
+function TypeParameterInstantiation(node) {
+  this.token("<");
+  this.printList(node.params, node, {});
+  this.token(">");
+}
+
+exports.TypeParameterDeclaration = TypeParameterInstantiation;
+function ObjectTypeAnnotation(node) {
+  var _this = this;
+
+  if (node.exact) {
+    this.token("{|");
+  } else {
+    this.token("{");
+  }
+
+  var props = node.properties.concat(node.callProperties, node.indexers);
+
+  if (props.length) {
+    this.space();
+
+    this.printJoin(props, node, {
+      addNewlines: function addNewlines(leading) {
+        if (leading && !props[0]) return 1;
+      },
+
+      indent: true,
+      statement: true,
+      iterator: function iterator() {
+        if (props.length !== 1) {
+          if (_this.format.flowCommaSeparator) {
+            _this.token(",");
+          } else {
+            _this.semicolon();
+          }
+          _this.space();
+        }
+      }
+    });
+
+    this.space();
+  }
+
+  if (node.exact) {
+    this.token("|}");
+  } else {
+    this.token("}");
+  }
+}
+
+function ObjectTypeCallProperty(node) {
+  if (node.static) {
+    this.word("static");
+    this.space();
+  }
+  this.print(node.value, node);
+}
+
+function ObjectTypeIndexer(node) {
+  if (node.static) {
+    this.word("static");
+    this.space();
+  }
+  this._variance(node);
+  this.token("[");
+  this.print(node.id, node);
+  this.token(":");
+  this.space();
+  this.print(node.key, node);
+  this.token("]");
+  this.token(":");
+  this.space();
+  this.print(node.value, node);
+}
+
+function ObjectTypeProperty(node) {
+  if (node.static) {
+    this.word("static");
+    this.space();
+  }
+  this._variance(node);
+  this.print(node.key, node);
+  if (node.optional) this.token("?");
+  this.token(":");
+  this.space();
+  this.print(node.value, node);
+}
+
+function ObjectTypeSpreadProperty(node) {
+  this.token("...");
+  this.print(node.argument, node);
+}
+
+function QualifiedTypeIdentifier(node) {
+  this.print(node.qualification, node);
+  this.token(".");
+  this.print(node.id, node);
+}
+
+function orSeparator() {
+  this.space();
+  this.token("|");
+  this.space();
+}
+
+function UnionTypeAnnotation(node) {
+  this.printJoin(node.types, node, { separator: orSeparator });
+}
+
+function TypeCastExpression(node) {
+  this.token("(");
+  this.print(node.expression, node);
+  this.print(node.typeAnnotation, node);
+  this.token(")");
+}
+
+function VoidTypeAnnotation() {
+  this.word("void");
+}
+},{"./types":43,"babel-types":151}],38:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.JSXAttribute = JSXAttribute;
+exports.JSXIdentifier = JSXIdentifier;
+exports.JSXNamespacedName = JSXNamespacedName;
+exports.JSXMemberExpression = JSXMemberExpression;
+exports.JSXSpreadAttribute = JSXSpreadAttribute;
+exports.JSXExpressionContainer = JSXExpressionContainer;
+exports.JSXSpreadChild = JSXSpreadChild;
+exports.JSXText = JSXText;
+exports.JSXElement = JSXElement;
+exports.JSXOpeningElement = JSXOpeningElement;
+exports.JSXClosingElement = JSXClosingElement;
+exports.JSXEmptyExpression = JSXEmptyExpression;
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function JSXAttribute(node) {
+  this.print(node.name, node);
+  if (node.value) {
+    this.token("=");
+    this.print(node.value, node);
+  }
+}
+
+function JSXIdentifier(node) {
+  this.word(node.name);
+}
+
+function JSXNamespacedName(node) {
+  this.print(node.namespace, node);
+  this.token(":");
+  this.print(node.name, node);
+}
+
+function JSXMemberExpression(node) {
+  this.print(node.object, node);
+  this.token(".");
+  this.print(node.property, node);
+}
+
+function JSXSpreadAttribute(node) {
+  this.token("{");
+  this.token("...");
+  this.print(node.argument, node);
+  this.token("}");
+}
+
+function JSXExpressionContainer(node) {
+  this.token("{");
+  this.print(node.expression, node);
+  this.token("}");
+}
+
+function JSXSpreadChild(node) {
+  this.token("{");
+  this.token("...");
+  this.print(node.expression, node);
+  this.token("}");
+}
+
+function JSXText(node) {
+  this.token(node.value);
+}
+
+function JSXElement(node) {
+  var open = node.openingElement;
+  this.print(open, node);
+  if (open.selfClosing) return;
+
+  this.indent();
+  for (var _iterator = node.children, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+    var _ref;
+
+    if (_isArray) {
+      if (_i >= _iterator.length) break;
+      _ref = _iterator[_i++];
+    } else {
+      _i = _iterator.next();
+      if (_i.done) break;
+      _ref = _i.value;
+    }
+
+    var child = _ref;
+
+    this.print(child, node);
+  }
+  this.dedent();
+
+  this.print(node.closingElement, node);
+}
+
+function spaceSeparator() {
+  this.space();
+}
+
+function JSXOpeningElement(node) {
+  this.token("<");
+  this.print(node.name, node);
+  if (node.attributes.length > 0) {
+    this.space();
+    this.printJoin(node.attributes, node, { separator: spaceSeparator });
+  }
+  if (node.selfClosing) {
+    this.space();
+    this.token("/>");
+  } else {
+    this.token(">");
+  }
+}
+
+function JSXClosingElement(node) {
+  this.token("</");
+  this.print(node.name, node);
+  this.token(">");
+}
+
+function JSXEmptyExpression() {}
+},{"babel-runtime/core-js/get-iterator":95}],39:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.FunctionDeclaration = undefined;
+exports._params = _params;
+exports._method = _method;
+exports.FunctionExpression = FunctionExpression;
+exports.ArrowFunctionExpression = ArrowFunctionExpression;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _params(node) {
+  var _this = this;
+
+  this.print(node.typeParameters, node);
+  this.token("(");
+  this.printList(node.params, node, {
+    iterator: function iterator(node) {
+      if (node.optional) _this.token("?");
+      _this.print(node.typeAnnotation, node);
+    }
+  });
+  this.token(")");
+
+  if (node.returnType) {
+    this.print(node.returnType, node);
+  }
+}
+
+function _method(node) {
+  var kind = node.kind;
+  var key = node.key;
+
+  if (kind === "method" || kind === "init") {
+    if (node.generator) {
+      this.token("*");
+    }
+  }
+
+  if (kind === "get" || kind === "set") {
+    this.word(kind);
+    this.space();
+  }
+
+  if (node.async) {
+    this.word("async");
+    this.space();
+  }
+
+  if (node.computed) {
+    this.token("[");
+    this.print(key, node);
+    this.token("]");
+  } else {
+    this.print(key, node);
+  }
+
+  this._params(node);
+  this.space();
+  this.print(node.body, node);
+}
+
+function FunctionExpression(node) {
+  if (node.async) {
+    this.word("async");
+    this.space();
+  }
+  this.word("function");
+  if (node.generator) this.token("*");
+
+  if (node.id) {
+    this.space();
+    this.print(node.id, node);
+  } else {
+    this.space();
+  }
+
+  this._params(node);
+  this.space();
+  this.print(node.body, node);
+}
+
+exports.FunctionDeclaration = FunctionExpression;
+function ArrowFunctionExpression(node) {
+  if (node.async) {
+    this.word("async");
+    this.space();
+  }
+
+  var firstParam = node.params[0];
+
+  if (node.params.length === 1 && t.isIdentifier(firstParam) && !hasTypes(node, firstParam)) {
+    this.print(firstParam, node);
+  } else {
+    this._params(node);
+  }
+
+  this.space();
+  this.token("=>");
+  this.space();
+
+  this.print(node.body, node);
+}
+
+function hasTypes(node, param) {
+  return node.typeParameters || node.returnType || param.typeAnnotation || param.optional || param.trailingComments;
+}
+},{"babel-types":151}],40:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.ImportSpecifier = ImportSpecifier;
+exports.ImportDefaultSpecifier = ImportDefaultSpecifier;
+exports.ExportDefaultSpecifier = ExportDefaultSpecifier;
+exports.ExportSpecifier = ExportSpecifier;
+exports.ExportNamespaceSpecifier = ExportNamespaceSpecifier;
+exports.ExportAllDeclaration = ExportAllDeclaration;
+exports.ExportNamedDeclaration = ExportNamedDeclaration;
+exports.ExportDefaultDeclaration = ExportDefaultDeclaration;
+exports.ImportDeclaration = ImportDeclaration;
+exports.ImportNamespaceSpecifier = ImportNamespaceSpecifier;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function ImportSpecifier(node) {
+  if (node.importKind === "type" || node.importKind === "typeof") {
+    this.word(node.importKind);
+    this.space();
+  }
+
+  this.print(node.imported, node);
+  if (node.local && node.local.name !== node.imported.name) {
+    this.space();
+    this.word("as");
+    this.space();
+    this.print(node.local, node);
+  }
+}
+
+function ImportDefaultSpecifier(node) {
+  this.print(node.local, node);
+}
+
+function ExportDefaultSpecifier(node) {
+  this.print(node.exported, node);
+}
+
+function ExportSpecifier(node) {
+  this.print(node.local, node);
+  if (node.exported && node.local.name !== node.exported.name) {
+    this.space();
+    this.word("as");
+    this.space();
+    this.print(node.exported, node);
+  }
+}
+
+function ExportNamespaceSpecifier(node) {
+  this.token("*");
+  this.space();
+  this.word("as");
+  this.space();
+  this.print(node.exported, node);
+}
+
+function ExportAllDeclaration(node) {
+  this.word("export");
+  this.space();
+  this.token("*");
+  this.space();
+  this.word("from");
+  this.space();
+  this.print(node.source, node);
+  this.semicolon();
+}
+
+function ExportNamedDeclaration() {
+  this.word("export");
+  this.space();
+  ExportDeclaration.apply(this, arguments);
+}
+
+function ExportDefaultDeclaration() {
+  this.word("export");
+  this.space();
+  this.word("default");
+  this.space();
+  ExportDeclaration.apply(this, arguments);
+}
+
+function ExportDeclaration(node) {
+  if (node.declaration) {
+    var declar = node.declaration;
+    this.print(declar, node);
+    if (!t.isStatement(declar)) this.semicolon();
+  } else {
+    if (node.exportKind === "type") {
+      this.word("type");
+      this.space();
+    }
+
+    var specifiers = node.specifiers.slice(0);
+
+    var hasSpecial = false;
+    while (true) {
+      var first = specifiers[0];
+      if (t.isExportDefaultSpecifier(first) || t.isExportNamespaceSpecifier(first)) {
+        hasSpecial = true;
+        this.print(specifiers.shift(), node);
+        if (specifiers.length) {
+          this.token(",");
+          this.space();
+        }
+      } else {
+        break;
+      }
+    }
+
+    if (specifiers.length || !specifiers.length && !hasSpecial) {
+      this.token("{");
+      if (specifiers.length) {
+        this.space();
+        this.printList(specifiers, node);
+        this.space();
+      }
+      this.token("}");
+    }
+
+    if (node.source) {
+      this.space();
+      this.word("from");
+      this.space();
+      this.print(node.source, node);
+    }
+
+    this.semicolon();
+  }
+}
+
+function ImportDeclaration(node) {
+  this.word("import");
+  this.space();
+
+  if (node.importKind === "type" || node.importKind === "typeof") {
+    this.word(node.importKind);
+    this.space();
+  }
+
+  var specifiers = node.specifiers.slice(0);
+  if (specifiers && specifiers.length) {
+    while (true) {
+      var first = specifiers[0];
+      if (t.isImportDefaultSpecifier(first) || t.isImportNamespaceSpecifier(first)) {
+        this.print(specifiers.shift(), node);
+        if (specifiers.length) {
+          this.token(",");
+          this.space();
+        }
+      } else {
+        break;
+      }
+    }
+
+    if (specifiers.length) {
+      this.token("{");
+      this.space();
+      this.printList(specifiers, node);
+      this.space();
+      this.token("}");
+    }
+
+    this.space();
+    this.word("from");
+    this.space();
+  }
+
+  this.print(node.source, node);
+  this.semicolon();
+}
+
+function ImportNamespaceSpecifier(node) {
+  this.token("*");
+  this.space();
+  this.word("as");
+  this.space();
+  this.print(node.local, node);
+}
+},{"babel-types":151}],41:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.ThrowStatement = exports.BreakStatement = exports.ReturnStatement = exports.ContinueStatement = exports.ForAwaitStatement = exports.ForOfStatement = exports.ForInStatement = undefined;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.WithStatement = WithStatement;
+exports.IfStatement = IfStatement;
+exports.ForStatement = ForStatement;
+exports.WhileStatement = WhileStatement;
+exports.DoWhileStatement = DoWhileStatement;
+exports.LabeledStatement = LabeledStatement;
+exports.TryStatement = TryStatement;
+exports.CatchClause = CatchClause;
+exports.SwitchStatement = SwitchStatement;
+exports.SwitchCase = SwitchCase;
+exports.DebuggerStatement = DebuggerStatement;
+exports.VariableDeclaration = VariableDeclaration;
+exports.VariableDeclarator = VariableDeclarator;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function WithStatement(node) {
+  this.word("with");
+  this.space();
+  this.token("(");
+  this.print(node.object, node);
+  this.token(")");
+  this.printBlock(node);
+}
+
+function IfStatement(node) {
+  this.word("if");
+  this.space();
+  this.token("(");
+  this.print(node.test, node);
+  this.token(")");
+  this.space();
+
+  var needsBlock = node.alternate && t.isIfStatement(getLastStatement(node.consequent));
+  if (needsBlock) {
+    this.token("{");
+    this.newline();
+    this.indent();
+  }
+
+  this.printAndIndentOnComments(node.consequent, node);
+
+  if (needsBlock) {
+    this.dedent();
+    this.newline();
+    this.token("}");
+  }
+
+  if (node.alternate) {
+    if (this.endsWith("}")) this.space();
+    this.word("else");
+    this.space();
+    this.printAndIndentOnComments(node.alternate, node);
+  }
+}
+
+function getLastStatement(statement) {
+  if (!t.isStatement(statement.body)) return statement;
+  return getLastStatement(statement.body);
+}
+
+function ForStatement(node) {
+  this.word("for");
+  this.space();
+  this.token("(");
+
+  this.inForStatementInitCounter++;
+  this.print(node.init, node);
+  this.inForStatementInitCounter--;
+  this.token(";");
+
+  if (node.test) {
+    this.space();
+    this.print(node.test, node);
+  }
+  this.token(";");
+
+  if (node.update) {
+    this.space();
+    this.print(node.update, node);
+  }
+
+  this.token(")");
+  this.printBlock(node);
+}
+
+function WhileStatement(node) {
+  this.word("while");
+  this.space();
+  this.token("(");
+  this.print(node.test, node);
+  this.token(")");
+  this.printBlock(node);
+}
+
+var buildForXStatement = function buildForXStatement(op) {
+  return function (node) {
+    this.word("for");
+    this.space();
+    if (op === "await") {
+      this.word("await");
+      this.space();
+    }
+    this.token("(");
+
+    this.print(node.left, node);
+    this.space();
+    this.word(op === "await" ? "of" : op);
+    this.space();
+    this.print(node.right, node);
+    this.token(")");
+    this.printBlock(node);
+  };
+};
+
+var ForInStatement = exports.ForInStatement = buildForXStatement("in");
+var ForOfStatement = exports.ForOfStatement = buildForXStatement("of");
+var ForAwaitStatement = exports.ForAwaitStatement = buildForXStatement("await");
+
+function DoWhileStatement(node) {
+  this.word("do");
+  this.space();
+  this.print(node.body, node);
+  this.space();
+  this.word("while");
+  this.space();
+  this.token("(");
+  this.print(node.test, node);
+  this.token(")");
+  this.semicolon();
+}
+
+function buildLabelStatement(prefix) {
+  var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "label";
+
+  return function (node) {
+    this.word(prefix);
+
+    var label = node[key];
+    if (label) {
+      this.space();
+
+      var terminatorState = this.startTerminatorless();
+      this.print(label, node);
+      this.endTerminatorless(terminatorState);
+    }
+
+    this.semicolon();
+  };
+}
+
+var ContinueStatement = exports.ContinueStatement = buildLabelStatement("continue");
+var ReturnStatement = exports.ReturnStatement = buildLabelStatement("return", "argument");
+var BreakStatement = exports.BreakStatement = buildLabelStatement("break");
+var ThrowStatement = exports.ThrowStatement = buildLabelStatement("throw", "argument");
+
+function LabeledStatement(node) {
+  this.print(node.label, node);
+  this.token(":");
+  this.space();
+  this.print(node.body, node);
+}
+
+function TryStatement(node) {
+  this.word("try");
+  this.space();
+  this.print(node.block, node);
+  this.space();
+
+  if (node.handlers) {
+    this.print(node.handlers[0], node);
+  } else {
+    this.print(node.handler, node);
+  }
+
+  if (node.finalizer) {
+    this.space();
+    this.word("finally");
+    this.space();
+    this.print(node.finalizer, node);
+  }
+}
+
+function CatchClause(node) {
+  this.word("catch");
+  this.space();
+  this.token("(");
+  this.print(node.param, node);
+  this.token(")");
+  this.space();
+  this.print(node.body, node);
+}
+
+function SwitchStatement(node) {
+  this.word("switch");
+  this.space();
+  this.token("(");
+  this.print(node.discriminant, node);
+  this.token(")");
+  this.space();
+  this.token("{");
+
+  this.printSequence(node.cases, node, {
+    indent: true,
+    addNewlines: function addNewlines(leading, cas) {
+      if (!leading && node.cases[node.cases.length - 1] === cas) return -1;
+    }
+  });
+
+  this.token("}");
+}
+
+function SwitchCase(node) {
+  if (node.test) {
+    this.word("case");
+    this.space();
+    this.print(node.test, node);
+    this.token(":");
+  } else {
+    this.word("default");
+    this.token(":");
+  }
+
+  if (node.consequent.length) {
+    this.newline();
+    this.printSequence(node.consequent, node, { indent: true });
+  }
+}
+
+function DebuggerStatement() {
+  this.word("debugger");
+  this.semicolon();
+}
+
+function variableDeclarationIdent() {
+  this.token(",");
+  this.newline();
+  if (this.endsWith("\n")) for (var i = 0; i < 4; i++) {
+    this.space(true);
+  }
+}
+
+function constDeclarationIdent() {
+  this.token(",");
+  this.newline();
+  if (this.endsWith("\n")) for (var i = 0; i < 6; i++) {
+    this.space(true);
+  }
+}
+
+function VariableDeclaration(node, parent) {
+  this.word(node.kind);
+  this.space();
+
+  var hasInits = false;
+
+  if (!t.isFor(parent)) {
+    for (var _iterator = node.declarations, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var declar = _ref;
+
+      if (declar.init) {
+        hasInits = true;
+      }
+    }
+  }
+
+  var separator = void 0;
+  if (hasInits) {
+    separator = node.kind === "const" ? constDeclarationIdent : variableDeclarationIdent;
+  }
+
+  this.printList(node.declarations, node, { separator: separator });
+
+  if (t.isFor(parent)) {
+    if (parent.left === node || parent.init === node) return;
+  }
+
+  this.semicolon();
+}
+
+function VariableDeclarator(node) {
+  this.print(node.id, node);
+  this.print(node.id.typeAnnotation, node);
+  if (node.init) {
+    this.space();
+    this.token("=");
+    this.space();
+    this.print(node.init, node);
+  }
+}
+},{"babel-runtime/core-js/get-iterator":95,"babel-types":151}],42:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.TaggedTemplateExpression = TaggedTemplateExpression;
+exports.TemplateElement = TemplateElement;
+exports.TemplateLiteral = TemplateLiteral;
+function TaggedTemplateExpression(node) {
+  this.print(node.tag, node);
+  this.print(node.quasi, node);
+}
+
+function TemplateElement(node, parent) {
+  var isFirst = parent.quasis[0] === node;
+  var isLast = parent.quasis[parent.quasis.length - 1] === node;
+
+  var value = (isFirst ? "`" : "}") + node.value.raw + (isLast ? "`" : "${");
+
+  this.token(value);
+}
+
+function TemplateLiteral(node) {
+  var quasis = node.quasis;
+
+  for (var i = 0; i < quasis.length; i++) {
+    this.print(quasis[i], node);
+
+    if (i + 1 < quasis.length) {
+      this.print(node.expressions[i], node);
+    }
+  }
+}
+},{}],43:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.ArrayPattern = exports.ObjectPattern = exports.RestProperty = exports.SpreadProperty = exports.SpreadElement = undefined;
+exports.Identifier = Identifier;
+exports.RestElement = RestElement;
+exports.ObjectExpression = ObjectExpression;
+exports.ObjectMethod = ObjectMethod;
+exports.ObjectProperty = ObjectProperty;
+exports.ArrayExpression = ArrayExpression;
+exports.RegExpLiteral = RegExpLiteral;
+exports.BooleanLiteral = BooleanLiteral;
+exports.NullLiteral = NullLiteral;
+exports.NumericLiteral = NumericLiteral;
+exports.StringLiteral = StringLiteral;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+var _jsesc = require("jsesc");
+
+var _jsesc2 = _interopRequireDefault(_jsesc);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function Identifier(node) {
+  if (node.variance) {
+    if (node.variance === "plus") {
+      this.token("+");
+    } else if (node.variance === "minus") {
+      this.token("-");
+    }
+  }
+
+  this.word(node.name);
+}
+
+function RestElement(node) {
+  this.token("...");
+  this.print(node.argument, node);
+}
+
+exports.SpreadElement = RestElement;
+exports.SpreadProperty = RestElement;
+exports.RestProperty = RestElement;
+function ObjectExpression(node) {
+  var props = node.properties;
+
+  this.token("{");
+  this.printInnerComments(node);
+
+  if (props.length) {
+    this.space();
+    this.printList(props, node, { indent: true, statement: true });
+    this.space();
+  }
+
+  this.token("}");
+}
+
+exports.ObjectPattern = ObjectExpression;
+function ObjectMethod(node) {
+  this.printJoin(node.decorators, node);
+  this._method(node);
+}
+
+function ObjectProperty(node) {
+  this.printJoin(node.decorators, node);
+
+  if (node.computed) {
+    this.token("[");
+    this.print(node.key, node);
+    this.token("]");
+  } else {
+    if (t.isAssignmentPattern(node.value) && t.isIdentifier(node.key) && node.key.name === node.value.left.name) {
+      this.print(node.value, node);
+      return;
+    }
+
+    this.print(node.key, node);
+
+    if (node.shorthand && t.isIdentifier(node.key) && t.isIdentifier(node.value) && node.key.name === node.value.name) {
+      return;
+    }
+  }
+
+  this.token(":");
+  this.space();
+  this.print(node.value, node);
+}
+
+function ArrayExpression(node) {
+  var elems = node.elements;
+  var len = elems.length;
+
+  this.token("[");
+  this.printInnerComments(node);
+
+  for (var i = 0; i < elems.length; i++) {
+    var elem = elems[i];
+    if (elem) {
+      if (i > 0) this.space();
+      this.print(elem, node);
+      if (i < len - 1) this.token(",");
+    } else {
+      this.token(",");
+    }
+  }
+
+  this.token("]");
+}
+
+exports.ArrayPattern = ArrayExpression;
+function RegExpLiteral(node) {
+  this.word("/" + node.pattern + "/" + node.flags);
+}
+
+function BooleanLiteral(node) {
+  this.word(node.value ? "true" : "false");
+}
+
+function NullLiteral() {
+  this.word("null");
+}
+
+function NumericLiteral(node) {
+  var raw = this.getPossibleRaw(node);
+  var value = node.value + "";
+  if (raw == null) {
+    this.number(value);
+  } else if (this.format.minified) {
+    this.number(raw.length < value.length ? raw : value);
+  } else {
+    this.number(raw);
+  }
+}
+
+function StringLiteral(node, parent) {
+  var raw = this.getPossibleRaw(node);
+  if (!this.format.minified && raw != null) {
+    this.token(raw);
+    return;
+  }
+
+  var opts = {
+    quotes: t.isJSX(parent) ? "double" : this.format.quotes,
+    wrap: true
+  };
+  if (this.format.jsonCompatibleStrings) {
+    opts.json = true;
+  }
+  var val = (0, _jsesc2.default)(node.value, opts);
+
+  return this.token(val);
+}
+},{"babel-types":151,"jsesc":296}],44:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.CodeGenerator = undefined;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require("babel-runtime/helpers/inherits");
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+exports.default = function (ast, opts, code) {
+  var gen = new Generator(ast, opts, code);
+  return gen.generate();
+};
+
+var _detectIndent = require("detect-indent");
+
+var _detectIndent2 = _interopRequireDefault(_detectIndent);
+
+var _sourceMap = require("./source-map");
+
+var _sourceMap2 = _interopRequireDefault(_sourceMap);
+
+var _babelMessages = require("babel-messages");
+
+var messages = _interopRequireWildcard(_babelMessages);
+
+var _printer = require("./printer");
+
+var _printer2 = _interopRequireDefault(_printer);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var Generator = function (_Printer) {
+  (0, _inherits3.default)(Generator, _Printer);
+
+  function Generator(ast) {
+    var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+    var code = arguments[2];
+    (0, _classCallCheck3.default)(this, Generator);
+
+    var tokens = ast.tokens || [];
+    var format = normalizeOptions(code, opts, tokens);
+    var map = opts.sourceMaps ? new _sourceMap2.default(opts, code) : null;
+
+    var _this = (0, _possibleConstructorReturn3.default)(this, _Printer.call(this, format, map, tokens));
+
+    _this.ast = ast;
+    return _this;
+  }
+
+  Generator.prototype.generate = function generate() {
+    return _Printer.prototype.generate.call(this, this.ast);
+  };
+
+  return Generator;
+}(_printer2.default);
+
+function normalizeOptions(code, opts, tokens) {
+  var style = "  ";
+  if (code && typeof code === "string") {
+    var indent = (0, _detectIndent2.default)(code).indent;
+    if (indent && indent !== " ") style = indent;
+  }
+
+  var format = {
+    auxiliaryCommentBefore: opts.auxiliaryCommentBefore,
+    auxiliaryCommentAfter: opts.auxiliaryCommentAfter,
+    shouldPrintComment: opts.shouldPrintComment,
+    retainLines: opts.retainLines,
+    retainFunctionParens: opts.retainFunctionParens,
+    comments: opts.comments == null || opts.comments,
+    compact: opts.compact,
+    minified: opts.minified,
+    concise: opts.concise,
+    quotes: opts.quotes || findCommonStringDelimiter(code, tokens),
+    jsonCompatibleStrings: opts.jsonCompatibleStrings,
+    indent: {
+      adjustMultilineComment: true,
+      style: style,
+      base: 0
+    },
+    flowCommaSeparator: opts.flowCommaSeparator
+  };
+
+  if (format.minified) {
+    format.compact = true;
+
+    format.shouldPrintComment = format.shouldPrintComment || function () {
+      return format.comments;
+    };
+  } else {
+    format.shouldPrintComment = format.shouldPrintComment || function (value) {
+      return format.comments || value.indexOf("@license") >= 0 || value.indexOf("@preserve") >= 0;
+    };
+  }
+
+  if (format.compact === "auto") {
+    format.compact = code.length > 500000;
+
+    if (format.compact) {
+      console.error("[BABEL] " + messages.get("codeGeneratorDeopt", opts.filename, "500KB"));
+    }
+  }
+
+  if (format.compact) {
+    format.indent.adjustMultilineComment = false;
+  }
+
+  return format;
+}
+
+function findCommonStringDelimiter(code, tokens) {
+  var DEFAULT_STRING_DELIMITER = "double";
+  if (!code) {
+    return DEFAULT_STRING_DELIMITER;
+  }
+
+  var occurrences = {
+    single: 0,
+    double: 0
+  };
+
+  var checked = 0;
+
+  for (var i = 0; i < tokens.length; i++) {
+    var token = tokens[i];
+    if (token.type.label !== "string") continue;
+
+    var raw = code.slice(token.start, token.end);
+    if (raw[0] === "'") {
+      occurrences.single++;
+    } else {
+      occurrences.double++;
+    }
+
+    checked++;
+    if (checked >= 3) break;
+  }
+  if (occurrences.single > occurrences.double) {
+    return "single";
+  } else {
+    return "double";
+  }
+}
+
+var CodeGenerator = exports.CodeGenerator = function () {
+  function CodeGenerator(ast, opts, code) {
+    (0, _classCallCheck3.default)(this, CodeGenerator);
+
+    this._generator = new Generator(ast, opts, code);
+  }
+
+  CodeGenerator.prototype.generate = function generate() {
+    return this._generator.generate();
+  };
+
+  return CodeGenerator;
+}();
+},{"./printer":48,"./source-map":49,"babel-messages":61,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/inherits":110,"babel-runtime/helpers/possibleConstructorReturn":112,"detect-indent":282}],45:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _keys = require("babel-runtime/core-js/object/keys");
+
+var _keys2 = _interopRequireDefault(_keys);
+
+exports.needsWhitespace = needsWhitespace;
+exports.needsWhitespaceBefore = needsWhitespaceBefore;
+exports.needsWhitespaceAfter = needsWhitespaceAfter;
+exports.needsParens = needsParens;
+
+var _whitespace = require("./whitespace");
+
+var _whitespace2 = _interopRequireDefault(_whitespace);
+
+var _parentheses = require("./parentheses");
+
+var parens = _interopRequireWildcard(_parentheses);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function expandAliases(obj) {
+  var newObj = {};
+
+  function add(type, func) {
+    var fn = newObj[type];
+    newObj[type] = fn ? function (node, parent, stack) {
+      var result = fn(node, parent, stack);
+
+      return result == null ? func(node, parent, stack) : result;
+    } : func;
+  }
+
+  for (var _iterator = (0, _keys2.default)(obj), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+    var _ref;
+
+    if (_isArray) {
+      if (_i >= _iterator.length) break;
+      _ref = _iterator[_i++];
+    } else {
+      _i = _iterator.next();
+      if (_i.done) break;
+      _ref = _i.value;
+    }
+
+    var type = _ref;
+
+
+    var aliases = t.FLIPPED_ALIAS_KEYS[type];
+    if (aliases) {
+      for (var _iterator2 = aliases, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+        var _ref2;
+
+        if (_isArray2) {
+          if (_i2 >= _iterator2.length) break;
+          _ref2 = _iterator2[_i2++];
+        } else {
+          _i2 = _iterator2.next();
+          if (_i2.done) break;
+          _ref2 = _i2.value;
+        }
+
+        var alias = _ref2;
+
+        add(alias, obj[type]);
+      }
+    } else {
+      add(type, obj[type]);
+    }
+  }
+
+  return newObj;
+}
+
+var expandedParens = expandAliases(parens);
+var expandedWhitespaceNodes = expandAliases(_whitespace2.default.nodes);
+var expandedWhitespaceList = expandAliases(_whitespace2.default.list);
+
+function find(obj, node, parent, printStack) {
+  var fn = obj[node.type];
+  return fn ? fn(node, parent, printStack) : null;
+}
+
+function isOrHasCallExpression(node) {
+  if (t.isCallExpression(node)) {
+    return true;
+  }
+
+  if (t.isMemberExpression(node)) {
+    return isOrHasCallExpression(node.object) || !node.computed && isOrHasCallExpression(node.property);
+  } else {
+    return false;
+  }
+}
+
+function needsWhitespace(node, parent, type) {
+  if (!node) return 0;
+
+  if (t.isExpressionStatement(node)) {
+    node = node.expression;
+  }
+
+  var linesInfo = find(expandedWhitespaceNodes, node, parent);
+
+  if (!linesInfo) {
+    var items = find(expandedWhitespaceList, node, parent);
+    if (items) {
+      for (var i = 0; i < items.length; i++) {
+        linesInfo = needsWhitespace(items[i], node, type);
+        if (linesInfo) break;
+      }
+    }
+  }
+
+  return linesInfo && linesInfo[type] || 0;
+}
+
+function needsWhitespaceBefore(node, parent) {
+  return needsWhitespace(node, parent, "before");
+}
+
+function needsWhitespaceAfter(node, parent) {
+  return needsWhitespace(node, parent, "after");
+}
+
+function needsParens(node, parent, printStack) {
+  if (!parent) return false;
+
+  if (t.isNewExpression(parent) && parent.callee === node) {
+    if (isOrHasCallExpression(node)) return true;
+  }
+
+  return find(expandedParens, node, parent, printStack);
+}
+},{"./parentheses":46,"./whitespace":47,"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/object/keys":102,"babel-types":151}],46:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.AwaitExpression = exports.FunctionTypeAnnotation = undefined;
+exports.NullableTypeAnnotation = NullableTypeAnnotation;
+exports.UpdateExpression = UpdateExpression;
+exports.ObjectExpression = ObjectExpression;
+exports.DoExpression = DoExpression;
+exports.Binary = Binary;
+exports.BinaryExpression = BinaryExpression;
+exports.SequenceExpression = SequenceExpression;
+exports.YieldExpression = YieldExpression;
+exports.ClassExpression = ClassExpression;
+exports.UnaryLike = UnaryLike;
+exports.FunctionExpression = FunctionExpression;
+exports.ArrowFunctionExpression = ArrowFunctionExpression;
+exports.ConditionalExpression = ConditionalExpression;
+exports.AssignmentExpression = AssignmentExpression;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+var PRECEDENCE = {
+  "||": 0,
+  "&&": 1,
+  "|": 2,
+  "^": 3,
+  "&": 4,
+  "==": 5,
+  "===": 5,
+  "!=": 5,
+  "!==": 5,
+  "<": 6,
+  ">": 6,
+  "<=": 6,
+  ">=": 6,
+  in: 6,
+  instanceof: 6,
+  ">>": 7,
+  "<<": 7,
+  ">>>": 7,
+  "+": 8,
+  "-": 8,
+  "*": 9,
+  "/": 9,
+  "%": 9,
+  "**": 10
+};
+
+function NullableTypeAnnotation(node, parent) {
+  return t.isArrayTypeAnnotation(parent);
+}
+
+exports.FunctionTypeAnnotation = NullableTypeAnnotation;
+function UpdateExpression(node, parent) {
+  return t.isMemberExpression(parent) && parent.object === node;
+}
+
+function ObjectExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack, { considerArrow: true });
+}
+
+function DoExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack);
+}
+
+function Binary(node, parent) {
+  if ((t.isCallExpression(parent) || t.isNewExpression(parent)) && parent.callee === node || t.isUnaryLike(parent) || t.isMemberExpression(parent) && parent.object === node || t.isAwaitExpression(parent)) {
+    return true;
+  }
+
+  if (t.isBinary(parent)) {
+    var parentOp = parent.operator;
+    var parentPos = PRECEDENCE[parentOp];
+
+    var nodeOp = node.operator;
+    var nodePos = PRECEDENCE[nodeOp];
+
+    if (parentPos === nodePos && parent.right === node && !t.isLogicalExpression(parent) || parentPos > nodePos) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+function BinaryExpression(node, parent) {
+  return node.operator === "in" && (t.isVariableDeclarator(parent) || t.isFor(parent));
+}
+
+function SequenceExpression(node, parent) {
+
+  if (t.isForStatement(parent) || t.isThrowStatement(parent) || t.isReturnStatement(parent) || t.isIfStatement(parent) && parent.test === node || t.isWhileStatement(parent) && parent.test === node || t.isForInStatement(parent) && parent.right === node || t.isSwitchStatement(parent) && parent.discriminant === node || t.isExpressionStatement(parent) && parent.expression === node) {
+    return false;
+  }
+
+  return true;
+}
+
+function YieldExpression(node, parent) {
+  return t.isBinary(parent) || t.isUnaryLike(parent) || t.isCallExpression(parent) || t.isMemberExpression(parent) || t.isNewExpression(parent) || t.isConditionalExpression(parent) && node === parent.test;
+}
+
+exports.AwaitExpression = YieldExpression;
+function ClassExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack, { considerDefaultExports: true });
+}
+
+function UnaryLike(node, parent) {
+  return t.isMemberExpression(parent, { object: node }) || t.isCallExpression(parent, { callee: node }) || t.isNewExpression(parent, { callee: node });
+}
+
+function FunctionExpression(node, parent, printStack) {
+  return isFirstInStatement(printStack, { considerDefaultExports: true });
+}
+
+function ArrowFunctionExpression(node, parent) {
+  if (t.isExportDeclaration(parent) || t.isBinaryExpression(parent) || t.isLogicalExpression(parent) || t.isUnaryExpression(parent) || t.isTaggedTemplateExpression(parent)) {
+    return true;
+  }
+
+  return UnaryLike(node, parent);
+}
+
+function ConditionalExpression(node, parent) {
+  if (t.isUnaryLike(parent) || t.isBinary(parent) || t.isConditionalExpression(parent, { test: node }) || t.isAwaitExpression(parent)) {
+    return true;
+  }
+
+  return UnaryLike(node, parent);
+}
+
+function AssignmentExpression(node) {
+  if (t.isObjectPattern(node.left)) {
+    return true;
+  } else {
+    return ConditionalExpression.apply(undefined, arguments);
+  }
+}
+
+function isFirstInStatement(printStack) {
+  var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
+      _ref$considerArrow = _ref.considerArrow,
+      considerArrow = _ref$considerArrow === undefined ? false : _ref$considerArrow,
+      _ref$considerDefaultE = _ref.considerDefaultExports,
+      considerDefaultExports = _ref$considerDefaultE === undefined ? false : _ref$considerDefaultE;
+
+  var i = printStack.length - 1;
+  var node = printStack[i];
+  i--;
+  var parent = printStack[i];
+  while (i > 0) {
+    if (t.isExpressionStatement(parent, { expression: node }) || t.isTaggedTemplateExpression(parent) || considerDefaultExports && t.isExportDefaultDeclaration(parent, { declaration: node }) || considerArrow && t.isArrowFunctionExpression(parent, { body: node })) {
+      return true;
+    }
+
+    if (t.isCallExpression(parent, { callee: node }) || t.isSequenceExpression(parent) && parent.expressions[0] === node || t.isMemberExpression(parent, { object: node }) || t.isConditional(parent, { test: node }) || t.isBinary(parent, { left: node }) || t.isAssignmentExpression(parent, { left: node })) {
+      node = parent;
+      i--;
+      parent = printStack[i];
+    } else {
+      return false;
+    }
+  }
+
+  return false;
+}
+},{"babel-types":151}],47:[function(require,module,exports){
+"use strict";
+
+var _map = require("lodash/map");
+
+var _map2 = _interopRequireDefault(_map);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function crawl(node) {
+  var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+  if (t.isMemberExpression(node)) {
+    crawl(node.object, state);
+    if (node.computed) crawl(node.property, state);
+  } else if (t.isBinary(node) || t.isAssignmentExpression(node)) {
+    crawl(node.left, state);
+    crawl(node.right, state);
+  } else if (t.isCallExpression(node)) {
+    state.hasCall = true;
+    crawl(node.callee, state);
+  } else if (t.isFunction(node)) {
+    state.hasFunction = true;
+  } else if (t.isIdentifier(node)) {
+    state.hasHelper = state.hasHelper || isHelper(node.callee);
+  }
+
+  return state;
+}
+
+function isHelper(node) {
+  if (t.isMemberExpression(node)) {
+    return isHelper(node.object) || isHelper(node.property);
+  } else if (t.isIdentifier(node)) {
+    return node.name === "require" || node.name[0] === "_";
+  } else if (t.isCallExpression(node)) {
+    return isHelper(node.callee);
+  } else if (t.isBinary(node) || t.isAssignmentExpression(node)) {
+    return t.isIdentifier(node.left) && isHelper(node.left) || isHelper(node.right);
+  } else {
+    return false;
+  }
+}
+
+function isType(node) {
+  return t.isLiteral(node) || t.isObjectExpression(node) || t.isArrayExpression(node) || t.isIdentifier(node) || t.isMemberExpression(node);
+}
+
+exports.nodes = {
+  AssignmentExpression: function AssignmentExpression(node) {
+    var state = crawl(node.right);
+    if (state.hasCall && state.hasHelper || state.hasFunction) {
+      return {
+        before: state.hasFunction,
+        after: true
+      };
+    }
+  },
+  SwitchCase: function SwitchCase(node, parent) {
+    return {
+      before: node.consequent.length || parent.cases[0] === node
+    };
+  },
+  LogicalExpression: function LogicalExpression(node) {
+    if (t.isFunction(node.left) || t.isFunction(node.right)) {
+      return {
+        after: true
+      };
+    }
+  },
+  Literal: function Literal(node) {
+    if (node.value === "use strict") {
+      return {
+        after: true
+      };
+    }
+  },
+  CallExpression: function CallExpression(node) {
+    if (t.isFunction(node.callee) || isHelper(node)) {
+      return {
+        before: true,
+        after: true
+      };
+    }
+  },
+  VariableDeclaration: function VariableDeclaration(node) {
+    for (var i = 0; i < node.declarations.length; i++) {
+      var declar = node.declarations[i];
+
+      var enabled = isHelper(declar.id) && !isType(declar.init);
+      if (!enabled) {
+        var state = crawl(declar.init);
+        enabled = isHelper(declar.init) && state.hasCall || state.hasFunction;
+      }
+
+      if (enabled) {
+        return {
+          before: true,
+          after: true
+        };
+      }
+    }
+  },
+  IfStatement: function IfStatement(node) {
+    if (t.isBlockStatement(node.consequent)) {
+      return {
+        before: true,
+        after: true
+      };
+    }
+  }
+};
+
+exports.nodes.ObjectProperty = exports.nodes.ObjectTypeProperty = exports.nodes.ObjectMethod = exports.nodes.SpreadProperty = function (node, parent) {
+  if (parent.properties[0] === node) {
+    return {
+      before: true
+    };
+  }
+};
+
+exports.list = {
+  VariableDeclaration: function VariableDeclaration(node) {
+    return (0, _map2.default)(node.declarations, "init");
+  },
+  ArrayExpression: function ArrayExpression(node) {
+    return node.elements;
+  },
+  ObjectExpression: function ObjectExpression(node) {
+    return node.properties;
+  }
+};
+
+[["Function", true], ["Class", true], ["Loop", true], ["LabeledStatement", true], ["SwitchStatement", true], ["TryStatement", true]].forEach(function (_ref) {
+  var type = _ref[0],
+      amounts = _ref[1];
+
+  if (typeof amounts === "boolean") {
+    amounts = { after: amounts, before: amounts };
+  }
+  [type].concat(t.FLIPPED_ALIAS_KEYS[type] || []).forEach(function (type) {
+    exports.nodes[type] = function () {
+      return amounts;
+    };
+  });
+});
+},{"babel-types":151,"lodash/map":500}],48:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _assign = require("babel-runtime/core-js/object/assign");
+
+var _assign2 = _interopRequireDefault(_assign);
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _stringify = require("babel-runtime/core-js/json/stringify");
+
+var _stringify2 = _interopRequireDefault(_stringify);
+
+var _weakSet = require("babel-runtime/core-js/weak-set");
+
+var _weakSet2 = _interopRequireDefault(_weakSet);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _find = require("lodash/find");
+
+var _find2 = _interopRequireDefault(_find);
+
+var _findLast = require("lodash/findLast");
+
+var _findLast2 = _interopRequireDefault(_findLast);
+
+var _isInteger = require("lodash/isInteger");
+
+var _isInteger2 = _interopRequireDefault(_isInteger);
+
+var _repeat = require("lodash/repeat");
+
+var _repeat2 = _interopRequireDefault(_repeat);
+
+var _buffer = require("./buffer");
+
+var _buffer2 = _interopRequireDefault(_buffer);
+
+var _node = require("./node");
+
+var n = _interopRequireWildcard(_node);
+
+var _whitespace = require("./whitespace");
+
+var _whitespace2 = _interopRequireDefault(_whitespace);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var SCIENTIFIC_NOTATION = /e/i;
+var ZERO_DECIMAL_INTEGER = /\.0+$/;
+var NON_DECIMAL_LITERAL = /^0[box]/;
+
+var Printer = function () {
+  function Printer(format, map, tokens) {
+    (0, _classCallCheck3.default)(this, Printer);
+    this.inForStatementInitCounter = 0;
+    this._printStack = [];
+    this._indent = 0;
+    this._insideAux = false;
+    this._printedCommentStarts = {};
+    this._parenPushNewlineState = null;
+    this._printAuxAfterOnNextUserNode = false;
+    this._printedComments = new _weakSet2.default();
+    this._endsWithInteger = false;
+    this._endsWithWord = false;
+
+    this.format = format || {};
+    this._buf = new _buffer2.default(map);
+    this._whitespace = tokens.length > 0 ? new _whitespace2.default(tokens) : null;
+  }
+
+  Printer.prototype.generate = function generate(ast) {
+    this.print(ast);
+    this._maybeAddAuxComment();
+
+    return this._buf.get();
+  };
+
+  Printer.prototype.indent = function indent() {
+    if (this.format.compact || this.format.concise) return;
+
+    this._indent++;
+  };
+
+  Printer.prototype.dedent = function dedent() {
+    if (this.format.compact || this.format.concise) return;
+
+    this._indent--;
+  };
+
+  Printer.prototype.semicolon = function semicolon() {
+    var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+
+    this._maybeAddAuxComment();
+    this._append(";", !force);
+  };
+
+  Printer.prototype.rightBrace = function rightBrace() {
+    if (this.format.minified) {
+      this._buf.removeLastSemicolon();
+    }
+    this.token("}");
+  };
+
+  Printer.prototype.space = function space() {
+    var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
+
+    if (this.format.compact) return;
+
+    if (this._buf.hasContent() && !this.endsWith(" ") && !this.endsWith("\n") || force) {
+      this._space();
+    }
+  };
+
+  Printer.prototype.word = function word(str) {
+    if (this._endsWithWord) this._space();
+
+    this._maybeAddAuxComment();
+    this._append(str);
+
+    this._endsWithWord = true;
+  };
+
+  Printer.prototype.number = function number(str) {
+    this.word(str);
+
+    this._endsWithInteger = (0, _isInteger2.default)(+str) && !NON_DECIMAL_LITERAL.test(str) && !SCIENTIFIC_NOTATION.test(str) && !ZERO_DECIMAL_INTEGER.test(str) && str[str.length - 1] !== ".";
+  };
+
+  Printer.prototype.token = function token(str) {
+    if (str === "--" && this.endsWith("!") || str[0] === "+" && this.endsWith("+") || str[0] === "-" && this.endsWith("-") || str[0] === "." && this._endsWithInteger) {
+      this._space();
+    }
+
+    this._maybeAddAuxComment();
+    this._append(str);
+  };
+
+  Printer.prototype.newline = function newline(i) {
+    if (this.format.retainLines || this.format.compact) return;
+
+    if (this.format.concise) {
+      this.space();
+      return;
+    }
+
+    if (this.endsWith("\n\n")) return;
+
+    if (typeof i !== "number") i = 1;
+
+    i = Math.min(2, i);
+    if (this.endsWith("{\n") || this.endsWith(":\n")) i--;
+    if (i <= 0) return;
+
+    for (var j = 0; j < i; j++) {
+      this._newline();
+    }
+  };
+
+  Printer.prototype.endsWith = function endsWith(str) {
+    return this._buf.endsWith(str);
+  };
+
+  Printer.prototype.removeTrailingNewline = function removeTrailingNewline() {
+    this._buf.removeTrailingNewline();
+  };
+
+  Printer.prototype.source = function source(prop, loc) {
+    this._catchUp(prop, loc);
+
+    this._buf.source(prop, loc);
+  };
+
+  Printer.prototype.withSource = function withSource(prop, loc, cb) {
+    this._catchUp(prop, loc);
+
+    this._buf.withSource(prop, loc, cb);
+  };
+
+  Printer.prototype._space = function _space() {
+    this._append(" ", true);
+  };
+
+  Printer.prototype._newline = function _newline() {
+    this._append("\n", true);
+  };
+
+  Printer.prototype._append = function _append(str) {
+    var queue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+    this._maybeAddParen(str);
+    this._maybeIndent(str);
+
+    if (queue) this._buf.queue(str);else this._buf.append(str);
+
+    this._endsWithWord = false;
+    this._endsWithInteger = false;
+  };
+
+  Printer.prototype._maybeIndent = function _maybeIndent(str) {
+    if (this._indent && this.endsWith("\n") && str[0] !== "\n") {
+      this._buf.queue(this._getIndent());
+    }
+  };
+
+  Printer.prototype._maybeAddParen = function _maybeAddParen(str) {
+    var parenPushNewlineState = this._parenPushNewlineState;
+    if (!parenPushNewlineState) return;
+    this._parenPushNewlineState = null;
+
+    var i = void 0;
+    for (i = 0; i < str.length && str[i] === " "; i++) {
+      continue;
+    }if (i === str.length) return;
+
+    var cha = str[i];
+    if (cha === "\n" || cha === "/") {
+      this.token("(");
+      this.indent();
+      parenPushNewlineState.printed = true;
+    }
+  };
+
+  Printer.prototype._catchUp = function _catchUp(prop, loc) {
+    if (!this.format.retainLines) return;
+
+    var pos = loc ? loc[prop] : null;
+    if (pos && pos.line !== null) {
+      var count = pos.line - this._buf.getCurrentLine();
+
+      for (var i = 0; i < count; i++) {
+        this._newline();
+      }
+    }
+  };
+
+  Printer.prototype._getIndent = function _getIndent() {
+    return (0, _repeat2.default)(this.format.indent.style, this._indent);
+  };
+
+  Printer.prototype.startTerminatorless = function startTerminatorless() {
+    return this._parenPushNewlineState = {
+      printed: false
+    };
+  };
+
+  Printer.prototype.endTerminatorless = function endTerminatorless(state) {
+    if (state.printed) {
+      this.dedent();
+      this.newline();
+      this.token(")");
+    }
+  };
+
+  Printer.prototype.print = function print(node, parent) {
+    var _this = this;
+
+    if (!node) return;
+
+    var oldConcise = this.format.concise;
+    if (node._compact) {
+      this.format.concise = true;
+    }
+
+    var printMethod = this[node.type];
+    if (!printMethod) {
+      throw new ReferenceError("unknown node of type " + (0, _stringify2.default)(node.type) + " with constructor " + (0, _stringify2.default)(node && node.constructor.name));
+    }
+
+    this._printStack.push(node);
+
+    var oldInAux = this._insideAux;
+    this._insideAux = !node.loc;
+    this._maybeAddAuxComment(this._insideAux && !oldInAux);
+
+    var needsParens = n.needsParens(node, parent, this._printStack);
+    if (this.format.retainFunctionParens && node.type === "FunctionExpression" && node.extra && node.extra.parenthesized) {
+      needsParens = true;
+    }
+    if (needsParens) this.token("(");
+
+    this._printLeadingComments(node, parent);
+
+    var loc = t.isProgram(node) || t.isFile(node) ? null : node.loc;
+    this.withSource("start", loc, function () {
+      _this[node.type](node, parent);
+    });
+
+    this._printTrailingComments(node, parent);
+
+    if (needsParens) this.token(")");
+
+    this._printStack.pop();
+
+    this.format.concise = oldConcise;
+    this._insideAux = oldInAux;
+  };
+
+  Printer.prototype._maybeAddAuxComment = function _maybeAddAuxComment(enteredPositionlessNode) {
+    if (enteredPositionlessNode) this._printAuxBeforeComment();
+    if (!this._insideAux) this._printAuxAfterComment();
+  };
+
+  Printer.prototype._printAuxBeforeComment = function _printAuxBeforeComment() {
+    if (this._printAuxAfterOnNextUserNode) return;
+    this._printAuxAfterOnNextUserNode = true;
+
+    var comment = this.format.auxiliaryCommentBefore;
+    if (comment) {
+      this._printComment({
+        type: "CommentBlock",
+        value: comment
+      });
+    }
+  };
+
+  Printer.prototype._printAuxAfterComment = function _printAuxAfterComment() {
+    if (!this._printAuxAfterOnNextUserNode) return;
+    this._printAuxAfterOnNextUserNode = false;
+
+    var comment = this.format.auxiliaryCommentAfter;
+    if (comment) {
+      this._printComment({
+        type: "CommentBlock",
+        value: comment
+      });
+    }
+  };
+
+  Printer.prototype.getPossibleRaw = function getPossibleRaw(node) {
+    var extra = node.extra;
+    if (extra && extra.raw != null && extra.rawValue != null && node.value === extra.rawValue) {
+      return extra.raw;
+    }
+  };
+
+  Printer.prototype.printJoin = function printJoin(nodes, parent) {
+    var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+
+    if (!nodes || !nodes.length) return;
+
+    if (opts.indent) this.indent();
+
+    var newlineOpts = {
+      addNewlines: opts.addNewlines
+    };
+
+    for (var i = 0; i < nodes.length; i++) {
+      var node = nodes[i];
+      if (!node) continue;
+
+      if (opts.statement) this._printNewline(true, node, parent, newlineOpts);
+
+      this.print(node, parent);
+
+      if (opts.iterator) {
+        opts.iterator(node, i);
+      }
+
+      if (opts.separator && i < nodes.length - 1) {
+        opts.separator.call(this);
+      }
+
+      if (opts.statement) this._printNewline(false, node, parent, newlineOpts);
+    }
+
+    if (opts.indent) this.dedent();
+  };
+
+  Printer.prototype.printAndIndentOnComments = function printAndIndentOnComments(node, parent) {
+    var indent = !!node.leadingComments;
+    if (indent) this.indent();
+    this.print(node, parent);
+    if (indent) this.dedent();
+  };
+
+  Printer.prototype.printBlock = function printBlock(parent) {
+    var node = parent.body;
+
+    if (!t.isEmptyStatement(node)) {
+      this.space();
+    }
+
+    this.print(node, parent);
+  };
+
+  Printer.prototype._printTrailingComments = function _printTrailingComments(node, parent) {
+    this._printComments(this._getComments(false, node, parent));
+  };
+
+  Printer.prototype._printLeadingComments = function _printLeadingComments(node, parent) {
+    this._printComments(this._getComments(true, node, parent));
+  };
+
+  Printer.prototype.printInnerComments = function printInnerComments(node) {
+    var indent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
+
+    if (!node.innerComments) return;
+    if (indent) this.indent();
+    this._printComments(node.innerComments);
+    if (indent) this.dedent();
+  };
+
+  Printer.prototype.printSequence = function printSequence(nodes, parent) {
+    var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+
+    opts.statement = true;
+    return this.printJoin(nodes, parent, opts);
+  };
+
+  Printer.prototype.printList = function printList(items, parent) {
+    var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+
+    if (opts.separator == null) {
+      opts.separator = commaSeparator;
+    }
+
+    return this.printJoin(items, parent, opts);
+  };
+
+  Printer.prototype._printNewline = function _printNewline(leading, node, parent, opts) {
+    var _this2 = this;
+
+    if (this.format.retainLines || this.format.compact) return;
+
+    if (this.format.concise) {
+      this.space();
+      return;
+    }
+
+    var lines = 0;
+
+    if (node.start != null && !node._ignoreUserWhitespace && this._whitespace) {
+      if (leading) {
+        var _comments = node.leadingComments;
+        var _comment = _comments && (0, _find2.default)(_comments, function (comment) {
+          return !!comment.loc && _this2.format.shouldPrintComment(comment.value);
+        });
+
+        lines = this._whitespace.getNewlinesBefore(_comment || node);
+      } else {
+        var _comments2 = node.trailingComments;
+        var _comment2 = _comments2 && (0, _findLast2.default)(_comments2, function (comment) {
+          return !!comment.loc && _this2.format.shouldPrintComment(comment.value);
+        });
+
+        lines = this._whitespace.getNewlinesAfter(_comment2 || node);
+      }
+    } else {
+      if (!leading) lines++;
+      if (opts.addNewlines) lines += opts.addNewlines(leading, node) || 0;
+
+      var needs = n.needsWhitespaceAfter;
+      if (leading) needs = n.needsWhitespaceBefore;
+      if (needs(node, parent)) lines++;
+
+      if (!this._buf.hasContent()) lines = 0;
+    }
+
+    this.newline(lines);
+  };
+
+  Printer.prototype._getComments = function _getComments(leading, node) {
+    return node && (leading ? node.leadingComments : node.trailingComments) || [];
+  };
+
+  Printer.prototype._printComment = function _printComment(comment) {
+    var _this3 = this;
+
+    if (!this.format.shouldPrintComment(comment.value)) return;
+
+    if (comment.ignore) return;
+
+    if (this._printedComments.has(comment)) return;
+    this._printedComments.add(comment);
+
+    if (comment.start != null) {
+      if (this._printedCommentStarts[comment.start]) return;
+      this._printedCommentStarts[comment.start] = true;
+    }
+
+    this.newline(this._whitespace ? this._whitespace.getNewlinesBefore(comment) : 0);
+
+    if (!this.endsWith("[") && !this.endsWith("{")) this.space();
+
+    var val = comment.type === "CommentLine" ? "//" + comment.value + "\n" : "/*" + comment.value + "*/";
+
+    if (comment.type === "CommentBlock" && this.format.indent.adjustMultilineComment) {
+      var offset = comment.loc && comment.loc.start.column;
+      if (offset) {
+        var newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
+        val = val.replace(newlineRegex, "\n");
+      }
+
+      var indentSize = Math.max(this._getIndent().length, this._buf.getCurrentColumn());
+      val = val.replace(/\n(?!$)/g, "\n" + (0, _repeat2.default)(" ", indentSize));
+    }
+
+    this.withSource("start", comment.loc, function () {
+      _this3._append(val);
+    });
+
+    this.newline((this._whitespace ? this._whitespace.getNewlinesAfter(comment) : 0) + (comment.type === "CommentLine" ? -1 : 0));
+  };
+
+  Printer.prototype._printComments = function _printComments(comments) {
+    if (!comments || !comments.length) return;
+
+    for (var _iterator = comments, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var _comment3 = _ref;
+
+      this._printComment(_comment3);
+    }
+  };
+
+  return Printer;
+}();
+
+exports.default = Printer;
+
+
+function commaSeparator() {
+  this.token(",");
+  this.space();
+}
+
+var _arr = [require("./generators/template-literals"), require("./generators/expressions"), require("./generators/statements"), require("./generators/classes"), require("./generators/methods"), require("./generators/modules"), require("./generators/types"), require("./generators/flow"), require("./generators/base"), require("./generators/jsx")];
+for (var _i2 = 0; _i2 < _arr.length; _i2++) {
+  var generator = _arr[_i2];
+  (0, _assign2.default)(Printer.prototype, generator);
+}
+module.exports = exports["default"];
+},{"./buffer":33,"./generators/base":34,"./generators/classes":35,"./generators/expressions":36,"./generators/flow":37,"./generators/jsx":38,"./generators/methods":39,"./generators/modules":40,"./generators/statements":41,"./generators/template-literals":42,"./generators/types":43,"./node":45,"./whitespace":50,"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/json/stringify":96,"babel-runtime/core-js/object/assign":99,"babel-runtime/core-js/weak-set":108,"babel-runtime/helpers/classCallCheck":109,"babel-types":151,"lodash/find":474,"lodash/findLast":476,"lodash/isInteger":489,"lodash/repeat":507}],49:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _keys = require("babel-runtime/core-js/object/keys");
+
+var _keys2 = _interopRequireDefault(_keys);
+
+var _typeof2 = require("babel-runtime/helpers/typeof");
+
+var _typeof3 = _interopRequireDefault(_typeof2);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _sourceMap = require("source-map");
+
+var _sourceMap2 = _interopRequireDefault(_sourceMap);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var SourceMap = function () {
+  function SourceMap(opts, code) {
+    (0, _classCallCheck3.default)(this, SourceMap);
+
+    this._cachedMap = null;
+    this._code = code;
+    this._opts = opts;
+    this._rawMappings = [];
+  }
+
+  SourceMap.prototype.get = function get() {
+    if (!this._cachedMap) {
+      var map = this._cachedMap = new _sourceMap2.default.SourceMapGenerator({
+        file: this._opts.sourceMapTarget,
+        sourceRoot: this._opts.sourceRoot
+      });
+
+      var code = this._code;
+      if (typeof code === "string") {
+        map.setSourceContent(this._opts.sourceFileName, code);
+      } else if ((typeof code === "undefined" ? "undefined" : (0, _typeof3.default)(code)) === "object") {
+        (0, _keys2.default)(code).forEach(function (sourceFileName) {
+          map.setSourceContent(sourceFileName, code[sourceFileName]);
+        });
+      }
+
+      this._rawMappings.forEach(map.addMapping, map);
+    }
+
+    return this._cachedMap.toJSON();
+  };
+
+  SourceMap.prototype.getRawMappings = function getRawMappings() {
+    return this._rawMappings.slice();
+  };
+
+  SourceMap.prototype.mark = function mark(generatedLine, generatedColumn, line, column, identifierName, filename) {
+    if (this._lastGenLine !== generatedLine && line === null) return;
+
+    if (this._lastGenLine === generatedLine && this._lastSourceLine === line && this._lastSourceColumn === column) {
+      return;
+    }
+
+    this._cachedMap = null;
+    this._lastGenLine = generatedLine;
+    this._lastSourceLine = line;
+    this._lastSourceColumn = column;
+
+    this._rawMappings.push({
+      name: identifierName || undefined,
+      generated: {
+        line: generatedLine,
+        column: generatedColumn
+      },
+      source: line == null ? undefined : filename || this._opts.sourceFileName,
+      original: line == null ? undefined : {
+        line: line,
+        column: column
+      }
+    });
+  };
+
+  return SourceMap;
+}();
+
+exports.default = SourceMap;
+module.exports = exports["default"];
+},{"babel-runtime/core-js/object/keys":102,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/typeof":113,"source-map":552}],50:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var Whitespace = function () {
+  function Whitespace(tokens) {
+    (0, _classCallCheck3.default)(this, Whitespace);
+
+    this.tokens = tokens;
+    this.used = {};
+  }
+
+  Whitespace.prototype.getNewlinesBefore = function getNewlinesBefore(node) {
+    var startToken = void 0;
+    var endToken = void 0;
+    var tokens = this.tokens;
+
+    var index = this._findToken(function (token) {
+      return token.start - node.start;
+    }, 0, tokens.length);
+    if (index >= 0) {
+      while (index && node.start === tokens[index - 1].start) {
+        --index;
+      }startToken = tokens[index - 1];
+      endToken = tokens[index];
+    }
+
+    return this._getNewlinesBetween(startToken, endToken);
+  };
+
+  Whitespace.prototype.getNewlinesAfter = function getNewlinesAfter(node) {
+    var startToken = void 0;
+    var endToken = void 0;
+    var tokens = this.tokens;
+
+    var index = this._findToken(function (token) {
+      return token.end - node.end;
+    }, 0, tokens.length);
+    if (index >= 0) {
+      while (index && node.end === tokens[index - 1].end) {
+        --index;
+      }startToken = tokens[index];
+      endToken = tokens[index + 1];
+      if (endToken.type.label === ",") endToken = tokens[index + 2];
+    }
+
+    if (endToken && endToken.type.label === "eof") {
+      return 1;
+    } else {
+      return this._getNewlinesBetween(startToken, endToken);
+    }
+  };
+
+  Whitespace.prototype._getNewlinesBetween = function _getNewlinesBetween(startToken, endToken) {
+    if (!endToken || !endToken.loc) return 0;
+
+    var start = startToken ? startToken.loc.end.line : 1;
+    var end = endToken.loc.start.line;
+    var lines = 0;
+
+    for (var line = start; line < end; line++) {
+      if (typeof this.used[line] === "undefined") {
+        this.used[line] = true;
+        lines++;
+      }
+    }
+
+    return lines;
+  };
+
+  Whitespace.prototype._findToken = function _findToken(test, start, end) {
+    if (start >= end) return -1;
+    var middle = start + end >>> 1;
+    var match = test(this.tokens[middle]);
+    if (match < 0) {
+      return this._findToken(test, middle + 1, end);
+    } else if (match > 0) {
+      return this._findToken(test, start, middle);
+    } else if (match === 0) {
+      return middle;
+    }
+    return -1;
+  };
+
+  return Whitespace;
+}();
+
+exports.default = Whitespace;
+module.exports = exports["default"];
+},{"babel-runtime/helpers/classCallCheck":109}],51:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (path) {
+  var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : path.scope;
+  var node = path.node;
+
+  var container = t.functionExpression(null, [], node.body, node.generator, node.async);
+
+  var callee = container;
+  var args = [];
+
+  (0, _babelHelperHoistVariables2.default)(path, function (id) {
+    return scope.push({ id: id });
+  });
+
+  var state = {
+    foundThis: false,
+    foundArguments: false
+  };
+
+  path.traverse(visitor, state);
+
+  if (state.foundArguments) {
+    callee = t.memberExpression(container, t.identifier("apply"));
+    args = [];
+
+    if (state.foundThis) {
+      args.push(t.thisExpression());
+    }
+
+    if (state.foundArguments) {
+      if (!state.foundThis) args.push(t.nullLiteral());
+      args.push(t.identifier("arguments"));
+    }
+  }
+
+  var call = t.callExpression(callee, args);
+  if (node.generator) call = t.yieldExpression(call, true);
+
+  return t.returnStatement(call);
+};
+
+var _babelHelperHoistVariables = require("babel-helper-hoist-variables");
+
+var _babelHelperHoistVariables2 = _interopRequireDefault(_babelHelperHoistVariables);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var visitor = {
+  enter: function enter(path, state) {
+    if (path.isThisExpression()) {
+      state.foundThis = true;
+    }
+
+    if (path.isReferencedIdentifier({ name: "arguments" })) {
+      state.foundArguments = true;
+    }
+  },
+  Function: function Function(path) {
+    path.skip();
+  }
+};
+
+module.exports = exports["default"];
+},{"babel-helper-hoist-variables":55,"babel-types":151}],52:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _keys = require("babel-runtime/core-js/object/keys");
+
+var _keys2 = _interopRequireDefault(_keys);
+
+exports.push = push;
+exports.hasComputed = hasComputed;
+exports.toComputedObjectFromClass = toComputedObjectFromClass;
+exports.toClassObject = toClassObject;
+exports.toDefineObject = toDefineObject;
+
+var _babelHelperFunctionName = require("babel-helper-function-name");
+
+var _babelHelperFunctionName2 = _interopRequireDefault(_babelHelperFunctionName);
+
+var _has = require("lodash/has");
+
+var _has2 = _interopRequireDefault(_has);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function toKind(node) {
+  if (t.isClassMethod(node) || t.isObjectMethod(node)) {
+    if (node.kind === "get" || node.kind === "set") {
+      return node.kind;
+    }
+  }
+
+  return "value";
+}
+
+function push(mutatorMap, node, kind, file, scope) {
+  var alias = t.toKeyAlias(node);
+
+  var map = {};
+  if ((0, _has2.default)(mutatorMap, alias)) map = mutatorMap[alias];
+  mutatorMap[alias] = map;
+
+  map._inherits = map._inherits || [];
+  map._inherits.push(node);
+
+  map._key = node.key;
+
+  if (node.computed) {
+    map._computed = true;
+  }
+
+  if (node.decorators) {
+    var decorators = map.decorators = map.decorators || t.arrayExpression([]);
+    decorators.elements = decorators.elements.concat(node.decorators.map(function (dec) {
+      return dec.expression;
+    }).reverse());
+  }
+
+  if (map.value || map.initializer) {
+    throw file.buildCodeFrameError(node, "Key conflict with sibling node");
+  }
+
+  var key = void 0,
+      value = void 0;
+
+  if (t.isObjectProperty(node) || t.isObjectMethod(node) || t.isClassMethod(node)) {
+    key = t.toComputedKey(node, node.key);
+  }
+
+  if (t.isObjectProperty(node) || t.isClassProperty(node)) {
+    value = node.value;
+  } else if (t.isObjectMethod(node) || t.isClassMethod(node)) {
+    value = t.functionExpression(null, node.params, node.body, node.generator, node.async);
+    value.returnType = node.returnType;
+  }
+
+  var inheritedKind = toKind(node);
+  if (!kind || inheritedKind !== "value") {
+    kind = inheritedKind;
+  }
+
+  if (scope && t.isStringLiteral(key) && (kind === "value" || kind === "initializer") && t.isFunctionExpression(value)) {
+    value = (0, _babelHelperFunctionName2.default)({ id: key, node: value, scope: scope });
+  }
+
+  if (value) {
+    t.inheritsComments(value, node);
+    map[kind] = value;
+  }
+
+  return map;
+}
+
+function hasComputed(mutatorMap) {
+  for (var key in mutatorMap) {
+    if (mutatorMap[key]._computed) {
+      return true;
+    }
+  }
+  return false;
+}
+
+function toComputedObjectFromClass(obj) {
+  var objExpr = t.arrayExpression([]);
+
+  for (var i = 0; i < obj.properties.length; i++) {
+    var prop = obj.properties[i];
+    var val = prop.value;
+    val.properties.unshift(t.objectProperty(t.identifier("key"), t.toComputedKey(prop)));
+    objExpr.elements.push(val);
+  }
+
+  return objExpr;
+}
+
+function toClassObject(mutatorMap) {
+  var objExpr = t.objectExpression([]);
+
+  (0, _keys2.default)(mutatorMap).forEach(function (mutatorMapKey) {
+    var map = mutatorMap[mutatorMapKey];
+    var mapNode = t.objectExpression([]);
+
+    var propNode = t.objectProperty(map._key, mapNode, map._computed);
+
+    (0, _keys2.default)(map).forEach(function (key) {
+      var node = map[key];
+      if (key[0] === "_") return;
+
+      var inheritNode = node;
+      if (t.isClassMethod(node) || t.isClassProperty(node)) node = node.value;
+
+      var prop = t.objectProperty(t.identifier(key), node);
+      t.inheritsComments(prop, inheritNode);
+      t.removeComments(inheritNode);
+
+      mapNode.properties.push(prop);
+    });
+
+    objExpr.properties.push(propNode);
+  });
+
+  return objExpr;
+}
+
+function toDefineObject(mutatorMap) {
+  (0, _keys2.default)(mutatorMap).forEach(function (key) {
+    var map = mutatorMap[key];
+    if (map.value) map.writable = t.booleanLiteral(true);
+    map.configurable = t.booleanLiteral(true);
+    map.enumerable = t.booleanLiteral(true);
+  });
+
+  return toClassObject(mutatorMap);
+}
+},{"babel-helper-function-name":53,"babel-runtime/core-js/object/keys":102,"babel-types":151,"lodash/has":479}],53:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (_ref) {
+  var node = _ref.node,
+      parent = _ref.parent,
+      scope = _ref.scope,
+      id = _ref.id;
+
+  if (node.id) return;
+
+  if ((t.isObjectProperty(parent) || t.isObjectMethod(parent, { kind: "method" })) && (!parent.computed || t.isLiteral(parent.key))) {
+    id = parent.key;
+  } else if (t.isVariableDeclarator(parent)) {
+    id = parent.id;
+
+    if (t.isIdentifier(id)) {
+      var binding = scope.parent.getBinding(id.name);
+      if (binding && binding.constant && scope.getBinding(id.name) === binding) {
+        node.id = id;
+        node.id[t.NOT_LOCAL_BINDING] = true;
+        return;
+      }
+    }
+  } else if (t.isAssignmentExpression(parent)) {
+    id = parent.left;
+  } else if (!id) {
+    return;
+  }
+
+  var name = void 0;
+  if (id && t.isLiteral(id)) {
+    name = id.value;
+  } else if (id && t.isIdentifier(id)) {
+    name = id.name;
+  } else {
+    return;
+  }
+
+  name = t.toBindingIdentifierName(name);
+  id = t.identifier(name);
+
+  id[t.NOT_LOCAL_BINDING] = true;
+
+  var state = visit(node, name, scope);
+  return wrap(state, node, id, scope) || node;
+};
+
+var _babelHelperGetFunctionArity = require("babel-helper-get-function-arity");
+
+var _babelHelperGetFunctionArity2 = _interopRequireDefault(_babelHelperGetFunctionArity);
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildPropertyMethodAssignmentWrapper = (0, _babelTemplate2.default)("\n  (function (FUNCTION_KEY) {\n    function FUNCTION_ID() {\n      return FUNCTION_KEY.apply(this, arguments);\n    }\n\n    FUNCTION_ID.toString = function () {\n      return FUNCTION_KEY.toString();\n    }\n\n    return FUNCTION_ID;\n  })(FUNCTION)\n");
+
+var buildGeneratorPropertyMethodAssignmentWrapper = (0, _babelTemplate2.default)("\n  (function (FUNCTION_KEY) {\n    function* FUNCTION_ID() {\n      return yield* FUNCTION_KEY.apply(this, arguments);\n    }\n\n    FUNCTION_ID.toString = function () {\n      return FUNCTION_KEY.toString();\n    };\n\n    return FUNCTION_ID;\n  })(FUNCTION)\n");
+
+var visitor = {
+  "ReferencedIdentifier|BindingIdentifier": function ReferencedIdentifierBindingIdentifier(path, state) {
+    if (path.node.name !== state.name) return;
+
+    var localDeclar = path.scope.getBindingIdentifier(state.name);
+    if (localDeclar !== state.outerDeclar) return;
+
+    state.selfReference = true;
+    path.stop();
+  }
+};
+
+function wrap(state, method, id, scope) {
+  if (state.selfReference) {
+    if (scope.hasBinding(id.name) && !scope.hasGlobal(id.name)) {
+      scope.rename(id.name);
+    } else {
+      if (!t.isFunction(method)) return;
+
+      var build = buildPropertyMethodAssignmentWrapper;
+      if (method.generator) build = buildGeneratorPropertyMethodAssignmentWrapper;
+      var _template = build({
+        FUNCTION: method,
+        FUNCTION_ID: id,
+        FUNCTION_KEY: scope.generateUidIdentifier(id.name)
+      }).expression;
+      _template.callee._skipModulesRemap = true;
+
+      var params = _template.callee.body.body[0].params;
+      for (var i = 0, len = (0, _babelHelperGetFunctionArity2.default)(method); i < len; i++) {
+        params.push(scope.generateUidIdentifier("x"));
+      }
+
+      return _template;
+    }
+  }
+
+  method.id = id;
+  scope.getProgramParent().references[id.name] = true;
+}
+
+function visit(node, name, scope) {
+  var state = {
+    selfAssignment: false,
+    selfReference: false,
+    outerDeclar: scope.getBindingIdentifier(name),
+    references: [],
+    name: name
+  };
+
+  var binding = scope.getOwnBinding(name);
+
+  if (binding) {
+    if (binding.kind === "param") {
+      state.selfReference = true;
+    } else {}
+  } else if (state.outerDeclar || scope.hasGlobal(name)) {
+    scope.traverse(node, visitor, state);
+  }
+
+  return state;
+}
+
+module.exports = exports["default"];
+},{"babel-helper-get-function-arity":54,"babel-template":114,"babel-types":151}],54:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (node) {
+  var params = node.params;
+  for (var i = 0; i < params.length; i++) {
+    var param = params[i];
+    if (t.isAssignmentPattern(param) || t.isRestElement(param)) {
+      return i;
+    }
+  }
+  return params.length;
+};
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+module.exports = exports["default"];
+},{"babel-types":151}],55:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (path, emit) {
+  var kind = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "var";
+
+  path.traverse(visitor, { kind: kind, emit: emit });
+};
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var visitor = {
+  Scope: function Scope(path, state) {
+    if (state.kind === "let") path.skip();
+  },
+  Function: function Function(path) {
+    path.skip();
+  },
+  VariableDeclaration: function VariableDeclaration(path, state) {
+    if (state.kind && path.node.kind !== state.kind) return;
+
+    var nodes = [];
+
+    var declarations = path.get("declarations");
+    var firstId = void 0;
+
+    for (var _iterator = declarations, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var declar = _ref;
+
+      firstId = declar.node.id;
+
+      if (declar.node.init) {
+        nodes.push(t.expressionStatement(t.assignmentExpression("=", declar.node.id, declar.node.init)));
+      }
+
+      for (var name in declar.getBindingIdentifiers()) {
+        state.emit(t.identifier(name), name);
+      }
+    }
+
+    if (path.parentPath.isFor({ left: path.node })) {
+      path.replaceWith(firstId);
+    } else {
+      path.replaceWithMultiple(nodes);
+    }
+  }
+};
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95,"babel-types":151}],56:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (callee, thisNode, args) {
+  if (args.length === 1 && t.isSpreadElement(args[0]) && t.isIdentifier(args[0].argument, { name: "arguments" })) {
+    return t.callExpression(t.memberExpression(callee, t.identifier("apply")), [thisNode, args[0].argument]);
+  } else {
+    return t.callExpression(t.memberExpression(callee, t.identifier("call")), [thisNode].concat(args));
+  }
+};
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+module.exports = exports["default"];
+},{"babel-types":151}],57:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.is = is;
+exports.pullFlag = pullFlag;
+
+var _pull = require("lodash/pull");
+
+var _pull2 = _interopRequireDefault(_pull);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function is(node, flag) {
+  return t.isRegExpLiteral(node) && node.flags.indexOf(flag) >= 0;
+}
+
+function pullFlag(node, flag) {
+  var flags = node.flags.split("");
+  if (node.flags.indexOf(flag) < 0) return;
+  (0, _pull2.default)(flags, flag);
+  node.flags = flags.join("");
+}
+},{"babel-types":151,"lodash/pull":505}],58:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+var _babelHelperOptimiseCallExpression = require("babel-helper-optimise-call-expression");
+
+var _babelHelperOptimiseCallExpression2 = _interopRequireDefault(_babelHelperOptimiseCallExpression);
+
+var _babelMessages = require("babel-messages");
+
+var messages = _interopRequireWildcard(_babelMessages);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var HARDCORE_THIS_REF = (0, _symbol2.default)();
+
+function isIllegalBareSuper(node, parent) {
+  if (!t.isSuper(node)) return false;
+  if (t.isMemberExpression(parent, { computed: false })) return false;
+  if (t.isCallExpression(parent, { callee: node })) return false;
+  return true;
+}
+
+function isMemberExpressionSuper(node) {
+  return t.isMemberExpression(node) && t.isSuper(node.object);
+}
+
+function getPrototypeOfExpression(objectRef, isStatic) {
+  var targetRef = isStatic ? objectRef : t.memberExpression(objectRef, t.identifier("prototype"));
+
+  return t.logicalExpression("||", t.memberExpression(targetRef, t.identifier("__proto__")), t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")), [targetRef]));
+}
+
+var visitor = {
+  Function: function Function(path) {
+    if (!path.inShadow("this")) {
+      path.skip();
+    }
+  },
+  ReturnStatement: function ReturnStatement(path, state) {
+    if (!path.inShadow("this")) {
+      state.returns.push(path);
+    }
+  },
+  ThisExpression: function ThisExpression(path, state) {
+    if (!path.node[HARDCORE_THIS_REF]) {
+      state.thises.push(path);
+    }
+  },
+  enter: function enter(path, state) {
+    var callback = state.specHandle;
+    if (state.isLoose) callback = state.looseHandle;
+
+    var isBareSuper = path.isCallExpression() && path.get("callee").isSuper();
+
+    var result = callback.call(state, path);
+
+    if (result) {
+      state.hasSuper = true;
+    }
+
+    if (isBareSuper) {
+      state.bareSupers.push(path);
+    }
+
+    if (result === true) {
+      path.requeue();
+    }
+
+    if (result !== true && result) {
+      if (Array.isArray(result)) {
+        path.replaceWithMultiple(result);
+      } else {
+        path.replaceWith(result);
+      }
+    }
+  }
+};
+
+var ReplaceSupers = function () {
+  function ReplaceSupers(opts) {
+    var inClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+    (0, _classCallCheck3.default)(this, ReplaceSupers);
+
+    this.forceSuperMemoisation = opts.forceSuperMemoisation;
+    this.methodPath = opts.methodPath;
+    this.methodNode = opts.methodNode;
+    this.superRef = opts.superRef;
+    this.isStatic = opts.isStatic;
+    this.hasSuper = false;
+    this.inClass = inClass;
+    this.isLoose = opts.isLoose;
+    this.scope = this.methodPath.scope;
+    this.file = opts.file;
+    this.opts = opts;
+
+    this.bareSupers = [];
+    this.returns = [];
+    this.thises = [];
+  }
+
+  ReplaceSupers.prototype.getObjectRef = function getObjectRef() {
+    return this.opts.objectRef || this.opts.getObjectRef();
+  };
+
+  ReplaceSupers.prototype.setSuperProperty = function setSuperProperty(property, value, isComputed) {
+    return t.callExpression(this.file.addHelper("set"), [getPrototypeOfExpression(this.getObjectRef(), this.isStatic), isComputed ? property : t.stringLiteral(property.name), value, t.thisExpression()]);
+  };
+
+  ReplaceSupers.prototype.getSuperProperty = function getSuperProperty(property, isComputed) {
+    return t.callExpression(this.file.addHelper("get"), [getPrototypeOfExpression(this.getObjectRef(), this.isStatic), isComputed ? property : t.stringLiteral(property.name), t.thisExpression()]);
+  };
+
+  ReplaceSupers.prototype.replace = function replace() {
+    this.methodPath.traverse(visitor, this);
+  };
+
+  ReplaceSupers.prototype.getLooseSuperProperty = function getLooseSuperProperty(id, parent) {
+    var methodNode = this.methodNode;
+    var superRef = this.superRef || t.identifier("Function");
+
+    if (parent.property === id) {
+      return;
+    } else if (t.isCallExpression(parent, { callee: id })) {
+      return;
+    } else if (t.isMemberExpression(parent) && !methodNode.static) {
+      return t.memberExpression(superRef, t.identifier("prototype"));
+    } else {
+      return superRef;
+    }
+  };
+
+  ReplaceSupers.prototype.looseHandle = function looseHandle(path) {
+    var node = path.node;
+    if (path.isSuper()) {
+      return this.getLooseSuperProperty(node, path.parent);
+    } else if (path.isCallExpression()) {
+      var callee = node.callee;
+      if (!t.isMemberExpression(callee)) return;
+      if (!t.isSuper(callee.object)) return;
+
+      t.appendToMemberExpression(callee, t.identifier("call"));
+      node.arguments.unshift(t.thisExpression());
+      return true;
+    }
+  };
+
+  ReplaceSupers.prototype.specHandleAssignmentExpression = function specHandleAssignmentExpression(ref, path, node) {
+    if (node.operator === "=") {
+      return this.setSuperProperty(node.left.property, node.right, node.left.computed);
+    } else {
+      ref = ref || path.scope.generateUidIdentifier("ref");
+      return [t.variableDeclaration("var", [t.variableDeclarator(ref, node.left)]), t.expressionStatement(t.assignmentExpression("=", node.left, t.binaryExpression(node.operator[0], ref, node.right)))];
+    }
+  };
+
+  ReplaceSupers.prototype.specHandle = function specHandle(path) {
+    var property = void 0;
+    var computed = void 0;
+    var args = void 0;
+
+    var parent = path.parent;
+    var node = path.node;
+
+    if (isIllegalBareSuper(node, parent)) {
+      throw path.buildCodeFrameError(messages.get("classesIllegalBareSuper"));
+    }
+
+    if (t.isCallExpression(node)) {
+      var callee = node.callee;
+      if (t.isSuper(callee)) {
+        return;
+      } else if (isMemberExpressionSuper(callee)) {
+        property = callee.property;
+        computed = callee.computed;
+        args = node.arguments;
+      }
+    } else if (t.isMemberExpression(node) && t.isSuper(node.object)) {
+      property = node.property;
+      computed = node.computed;
+    } else if (t.isUpdateExpression(node) && isMemberExpressionSuper(node.argument)) {
+      var binary = t.binaryExpression(node.operator[0], node.argument, t.numericLiteral(1));
+      if (node.prefix) {
+        return this.specHandleAssignmentExpression(null, path, binary);
+      } else {
+        var ref = path.scope.generateUidIdentifier("ref");
+        return this.specHandleAssignmentExpression(ref, path, binary).concat(t.expressionStatement(ref));
+      }
+    } else if (t.isAssignmentExpression(node) && isMemberExpressionSuper(node.left)) {
+      return this.specHandleAssignmentExpression(null, path, node);
+    }
+
+    if (!property) return;
+
+    var superProperty = this.getSuperProperty(property, computed);
+
+    if (args) {
+      return this.optimiseCall(superProperty, args);
+    } else {
+      return superProperty;
+    }
+  };
+
+  ReplaceSupers.prototype.optimiseCall = function optimiseCall(callee, args) {
+    var thisNode = t.thisExpression();
+    thisNode[HARDCORE_THIS_REF] = true;
+    return (0, _babelHelperOptimiseCallExpression2.default)(callee, thisNode, args);
+  };
+
+  return ReplaceSupers;
+}();
+
+exports.default = ReplaceSupers;
+module.exports = exports["default"];
+},{"babel-helper-optimise-call-expression":56,"babel-messages":61,"babel-runtime/core-js/symbol":104,"babel-runtime/helpers/classCallCheck":109,"babel-types":151}],59:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var helpers = {};
+exports.default = helpers;
+
+
+helpers.typeof = (0, _babelTemplate2.default)("\n  (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\")\n    ? function (obj) { return typeof obj; }\n    : function (obj) {\n        return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype\n          ? \"symbol\"\n          : typeof obj;\n      };\n");
+
+helpers.jsx = (0, _babelTemplate2.default)("\n  (function () {\n    var REACT_ELEMENT_TYPE = (typeof Symbol === \"function\" && Symbol.for && Symbol.for(\"react.element\")) || 0xeac7;\n\n    return function createRawReactElement (type, props, key, children) {\n      var defaultProps = type && type.defaultProps;\n      var childrenLength = arguments.length - 3;\n\n      if (!props && childrenLength !== 0) {\n        // If we're going to assign props.children, we create a new object now\n        // to avoid mutating defaultProps.\n        props = {};\n      }\n      if (props && defaultProps) {\n        for (var propName in defaultProps) {\n          if (props[propName] === void 0) {\n            props[propName] = defaultProps[propName];\n          }\n        }\n      } else if (!props) {\n        props = defaultProps || {};\n      }\n\n      if (childrenLength === 1) {\n        props.children = children;\n      } else if (childrenLength > 1) {\n        var childArray = Array(childrenLength);\n        for (var i = 0; i < childrenLength; i++) {\n          childArray[i] = arguments[i + 3];\n        }\n        props.children = childArray;\n      }\n\n      return {\n        $$typeof: REACT_ELEMENT_TYPE,\n        type: type,\n        key: key === undefined ? null : '' + key,\n        ref: null,\n        props: props,\n        _owner: null,\n      };\n    };\n\n  })()\n");
+
+helpers.asyncIterator = (0, _babelTemplate2.default)("\n  (function (iterable) {\n    if (typeof Symbol === \"function\") {\n      if (Symbol.asyncIterator) {\n        var method = iterable[Symbol.asyncIterator];\n        if (method != null) return method.call(iterable);\n      }\n      if (Symbol.iterator) {\n        return iterable[Symbol.iterator]();\n      }\n    }\n    throw new TypeError(\"Object is not async iterable\");\n  })\n");
+
+helpers.asyncGenerator = (0, _babelTemplate2.default)("\n  (function () {\n    function AwaitValue(value) {\n      this.value = value;\n    }\n\n    function AsyncGenerator(gen) {\n      var front, back;\n\n      function send(key, arg) {\n        return new Promise(function (resolve, reject) {\n          var request = {\n            key: key,\n            arg: arg,\n            resolve: resolve,\n            reject: reject,\n            next: null\n          };\n\n          if (back) {\n            back = back.next = request;\n          } else {\n            front = back = request;\n            resume(key, arg);\n          }\n        });\n      }\n\n      function resume(key, arg) {\n        try {\n          var result = gen[key](arg)\n          var value = result.value;\n          if (value instanceof AwaitValue) {\n            Promise.resolve(value.value).then(\n              function (arg) { resume(\"next\", arg); },\n              function (arg) { resume(\"throw\", arg); });\n          } else {\n            settle(result.done ? \"return\" : \"normal\", result.value);\n          }\n        } catch (err) {\n          settle(\"throw\", err);\n        }\n      }\n\n      function settle(type, value) {\n        switch (type) {\n          case \"return\":\n            front.resolve({ value: value, done: true });\n            break;\n          case \"throw\":\n            front.reject(value);\n            break;\n          default:\n            front.resolve({ value: value, done: false });\n            break;\n        }\n\n        front = front.next;\n        if (front) {\n          resume(front.key, front.arg);\n        } else {\n          back = null;\n        }\n      }\n\n      this._invoke = send;\n\n      // Hide \"return\" method if generator return is not supported\n      if (typeof gen.return !== \"function\") {\n        this.return = undefined;\n      }\n    }\n\n    if (typeof Symbol === \"function\" && Symbol.asyncIterator) {\n      AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; };\n    }\n\n    AsyncGenerator.prototype.next = function (arg) { return this._invoke(\"next\", arg); };\n    AsyncGenerator.prototype.throw = function (arg) { return this._invoke(\"throw\", arg); };\n    AsyncGenerator.prototype.return = function (arg) { return this._invoke(\"return\", arg); };\n\n    return {\n      wrap: function (fn) {\n        return function () {\n          return new AsyncGenerator(fn.apply(this, arguments));\n        };\n      },\n      await: function (value) {\n        return new AwaitValue(value);\n      }\n    };\n\n  })()\n");
+
+helpers.asyncGeneratorDelegate = (0, _babelTemplate2.default)("\n  (function (inner, awaitWrap) {\n    var iter = {}, waiting = false;\n\n    function pump(key, value) {\n      waiting = true;\n      value = new Promise(function (resolve) { resolve(inner[key](value)); });\n      return { done: false, value: awaitWrap(value) };\n    };\n\n    if (typeof Symbol === \"function\" && Symbol.iterator) {\n      iter[Symbol.iterator] = function () { return this; };\n    }\n\n    iter.next = function (value) {\n      if (waiting) {\n        waiting = false;\n        return value;\n      }\n      return pump(\"next\", value);\n    };\n\n    if (typeof inner.throw === \"function\") {\n      iter.throw = function (value) {\n        if (waiting) {\n          waiting = false;\n          throw value;\n        }\n        return pump(\"throw\", value);\n      };\n    }\n\n    if (typeof inner.return === \"function\") {\n      iter.return = function (value) {\n        return pump(\"return\", value);\n      };\n    }\n\n    return iter;\n  })\n");
+
+helpers.asyncToGenerator = (0, _babelTemplate2.default)("\n  (function (fn) {\n    return function () {\n      var gen = fn.apply(this, arguments);\n      return new Promise(function (resolve, reject) {\n        function step(key, arg) {\n          try {\n            var info = gen[key](arg);\n            var value = info.value;\n          } catch (error) {\n            reject(error);\n            return;\n          }\n\n          if (info.done) {\n            resolve(value);\n          } else {\n            return Promise.resolve(value).then(function (value) {\n              step(\"next\", value);\n            }, function (err) {\n              step(\"throw\", err);\n            });\n          }\n        }\n\n        return step(\"next\");\n      });\n    };\n  })\n");
+
+helpers.classCallCheck = (0, _babelTemplate2.default)("\n  (function (instance, Constructor) {\n    if (!(instance instanceof Constructor)) {\n      throw new TypeError(\"Cannot call a class as a function\");\n    }\n  });\n");
+
+helpers.createClass = (0, _babelTemplate2.default)("\n  (function() {\n    function defineProperties(target, props) {\n      for (var i = 0; i < props.length; i ++) {\n        var descriptor = props[i];\n        descriptor.enumerable = descriptor.enumerable || false;\n        descriptor.configurable = true;\n        if (\"value\" in descriptor) descriptor.writable = true;\n        Object.defineProperty(target, descriptor.key, descriptor);\n      }\n    }\n\n    return function (Constructor, protoProps, staticProps) {\n      if (protoProps) defineProperties(Constructor.prototype, protoProps);\n      if (staticProps) defineProperties(Constructor, staticProps);\n      return Constructor;\n    };\n  })()\n");
+
+helpers.defineEnumerableProperties = (0, _babelTemplate2.default)("\n  (function (obj, descs) {\n    for (var key in descs) {\n      var desc = descs[key];\n      desc.configurable = desc.enumerable = true;\n      if (\"value\" in desc) desc.writable = true;\n      Object.defineProperty(obj, key, desc);\n    }\n    return obj;\n  })\n");
+
+helpers.defaults = (0, _babelTemplate2.default)("\n  (function (obj, defaults) {\n    var keys = Object.getOwnPropertyNames(defaults);\n    for (var i = 0; i < keys.length; i++) {\n      var key = keys[i];\n      var value = Object.getOwnPropertyDescriptor(defaults, key);\n      if (value && value.configurable && obj[key] === undefined) {\n        Object.defineProperty(obj, key, value);\n      }\n    }\n    return obj;\n  })\n");
+
+helpers.defineProperty = (0, _babelTemplate2.default)("\n  (function (obj, key, value) {\n    // Shortcircuit the slow defineProperty path when possible.\n    // We are trying to avoid issues where setters defined on the\n    // prototype cause side effects under the fast path of simple\n    // assignment. By checking for existence of the property with\n    // the in operator, we can optimize most of this overhead away.\n    if (key in obj) {\n      Object.defineProperty(obj, key, {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    } else {\n      obj[key] = value;\n    }\n    return obj;\n  });\n");
+
+helpers.extends = (0, _babelTemplate2.default)("\n  Object.assign || (function (target) {\n    for (var i = 1; i < arguments.length; i++) {\n      var source = arguments[i];\n      for (var key in source) {\n        if (Object.prototype.hasOwnProperty.call(source, key)) {\n          target[key] = source[key];\n        }\n      }\n    }\n    return target;\n  })\n");
+
+helpers.get = (0, _babelTemplate2.default)("\n  (function get(object, property, receiver) {\n    if (object === null) object = Function.prototype;\n\n    var desc = Object.getOwnPropertyDescriptor(object, property);\n\n    if (desc === undefined) {\n      var parent = Object.getPrototypeOf(object);\n\n      if (parent === null) {\n        return undefined;\n      } else {\n        return get(parent, property, receiver);\n      }\n    } else if (\"value\" in desc) {\n      return desc.value;\n    } else {\n      var getter = desc.get;\n\n      if (getter === undefined) {\n        return undefined;\n      }\n\n      return getter.call(receiver);\n    }\n  });\n");
+
+helpers.inherits = (0, _babelTemplate2.default)("\n  (function (subClass, superClass) {\n    if (typeof superClass !== \"function\" && superClass !== null) {\n      throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass);\n    }\n    subClass.prototype = Object.create(superClass && superClass.prototype, {\n      constructor: {\n        value: subClass,\n        enumerable: false,\n        writable: true,\n        configurable: true\n      }\n    });\n    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n  })\n");
+
+helpers.instanceof = (0, _babelTemplate2.default)("\n  (function (left, right) {\n    if (right != null && typeof Symbol !== \"undefined\" && right[Symbol.hasInstance]) {\n      return right[Symbol.hasInstance](left);\n    } else {\n      return left instanceof right;\n    }\n  });\n");
+
+helpers.interopRequireDefault = (0, _babelTemplate2.default)("\n  (function (obj) {\n    return obj && obj.__esModule ? obj : { default: obj };\n  })\n");
+
+helpers.interopRequireWildcard = (0, _babelTemplate2.default)("\n  (function (obj) {\n    if (obj && obj.__esModule) {\n      return obj;\n    } else {\n      var newObj = {};\n      if (obj != null) {\n        for (var key in obj) {\n          if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];\n        }\n      }\n      newObj.default = obj;\n      return newObj;\n    }\n  })\n");
+
+helpers.newArrowCheck = (0, _babelTemplate2.default)("\n  (function (innerThis, boundThis) {\n    if (innerThis !== boundThis) {\n      throw new TypeError(\"Cannot instantiate an arrow function\");\n    }\n  });\n");
+
+helpers.objectDestructuringEmpty = (0, _babelTemplate2.default)("\n  (function (obj) {\n    if (obj == null) throw new TypeError(\"Cannot destructure undefined\");\n  });\n");
+
+helpers.objectWithoutProperties = (0, _babelTemplate2.default)("\n  (function (obj, keys) {\n    var target = {};\n    for (var i in obj) {\n      if (keys.indexOf(i) >= 0) continue;\n      if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;\n      target[i] = obj[i];\n    }\n    return target;\n  })\n");
+
+helpers.possibleConstructorReturn = (0, _babelTemplate2.default)("\n  (function (self, call) {\n    if (!self) {\n      throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n    }\n    return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\n  });\n");
+
+helpers.selfGlobal = (0, _babelTemplate2.default)("\n  typeof global === \"undefined\" ? self : global\n");
+
+helpers.set = (0, _babelTemplate2.default)("\n  (function set(object, property, value, receiver) {\n    var desc = Object.getOwnPropertyDescriptor(object, property);\n\n    if (desc === undefined) {\n      var parent = Object.getPrototypeOf(object);\n\n      if (parent !== null) {\n        set(parent, property, value, receiver);\n      }\n    } else if (\"value\" in desc && desc.writable) {\n      desc.value = value;\n    } else {\n      var setter = desc.set;\n\n      if (setter !== undefined) {\n        setter.call(receiver, value);\n      }\n    }\n\n    return value;\n  });\n");
+
+helpers.slicedToArray = (0, _babelTemplate2.default)("\n  (function () {\n    // Broken out into a separate function to avoid deoptimizations due to the try/catch for the\n    // array iterator case.\n    function sliceIterator(arr, i) {\n      // this is an expanded form of `for...of` that properly supports abrupt completions of\n      // iterators etc. variable names have been minimised to reduce the size of this massive\n      // helper. sometimes spec compliancy is annoying :(\n      //\n      // _n = _iteratorNormalCompletion\n      // _d = _didIteratorError\n      // _e = _iteratorError\n      // _i = _iterator\n      // _s = _step\n\n      var _arr = [];\n      var _n = true;\n      var _d = false;\n      var _e = undefined;\n      try {\n        for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {\n          _arr.push(_s.value);\n          if (i && _arr.length === i) break;\n        }\n      } catch (err) {\n        _d = true;\n        _e = err;\n      } finally {\n        try {\n          if (!_n && _i[\"return\"]) _i[\"return\"]();\n        } finally {\n          if (_d) throw _e;\n        }\n      }\n      return _arr;\n    }\n\n    return function (arr, i) {\n      if (Array.isArray(arr)) {\n        return arr;\n      } else if (Symbol.iterator in Object(arr)) {\n        return sliceIterator(arr, i);\n      } else {\n        throw new TypeError(\"Invalid attempt to destructure non-iterable instance\");\n      }\n    };\n  })();\n");
+
+helpers.slicedToArrayLoose = (0, _babelTemplate2.default)("\n  (function (arr, i) {\n    if (Array.isArray(arr)) {\n      return arr;\n    } else if (Symbol.iterator in Object(arr)) {\n      var _arr = [];\n      for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {\n        _arr.push(_step.value);\n        if (i && _arr.length === i) break;\n      }\n      return _arr;\n    } else {\n      throw new TypeError(\"Invalid attempt to destructure non-iterable instance\");\n    }\n  });\n");
+
+helpers.taggedTemplateLiteral = (0, _babelTemplate2.default)("\n  (function (strings, raw) {\n    return Object.freeze(Object.defineProperties(strings, {\n        raw: { value: Object.freeze(raw) }\n    }));\n  });\n");
+
+helpers.taggedTemplateLiteralLoose = (0, _babelTemplate2.default)("\n  (function (strings, raw) {\n    strings.raw = raw;\n    return strings;\n  });\n");
+
+helpers.temporalRef = (0, _babelTemplate2.default)("\n  (function (val, name, undef) {\n    if (val === undef) {\n      throw new ReferenceError(name + \" is not defined - temporal dead zone\");\n    } else {\n      return val;\n    }\n  })\n");
+
+helpers.temporalUndefined = (0, _babelTemplate2.default)("\n  ({})\n");
+
+helpers.toArray = (0, _babelTemplate2.default)("\n  (function (arr) {\n    return Array.isArray(arr) ? arr : Array.from(arr);\n  });\n");
+
+helpers.toConsumableArray = (0, _babelTemplate2.default)("\n  (function (arr) {\n    if (Array.isArray(arr)) {\n      for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];\n      return arr2;\n    } else {\n      return Array.from(arr);\n    }\n  });\n");
+module.exports = exports["default"];
+},{"babel-template":114}],60:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.list = undefined;
+
+var _keys = require("babel-runtime/core-js/object/keys");
+
+var _keys2 = _interopRequireDefault(_keys);
+
+exports.get = get;
+
+var _helpers = require("./helpers");
+
+var _helpers2 = _interopRequireDefault(_helpers);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function get(name) {
+  var fn = _helpers2.default[name];
+  if (!fn) throw new ReferenceError("Unknown helper " + name);
+
+  return fn().expression;
+}
+
+var list = exports.list = (0, _keys2.default)(_helpers2.default).map(function (name) {
+  return name.replace(/^_/, "");
+}).filter(function (name) {
+  return name !== "__esModule";
+});
+
+exports.default = get;
+},{"./helpers":59,"babel-runtime/core-js/object/keys":102}],61:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.MESSAGES = undefined;
+
+var _stringify = require("babel-runtime/core-js/json/stringify");
+
+var _stringify2 = _interopRequireDefault(_stringify);
+
+exports.get = get;
+exports.parseArgs = parseArgs;
+
+var _util = require("util");
+
+var util = _interopRequireWildcard(_util);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var MESSAGES = exports.MESSAGES = {
+  tailCallReassignmentDeopt: "Function reference has been reassigned, so it will probably be dereferenced, therefore we can't optimise this with confidence",
+  classesIllegalBareSuper: "Illegal use of bare super",
+  classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead",
+  scopeDuplicateDeclaration: "Duplicate declaration $1",
+  settersNoRest: "Setters aren't allowed to have a rest",
+  noAssignmentsInForHead: "No assignments allowed in for-in/of head",
+  expectedMemberExpressionOrIdentifier: "Expected type MemberExpression or Identifier",
+  invalidParentForThisNode: "We don't know how to handle this node within the current parent - please open an issue",
+  readOnly: "$1 is read-only",
+  unknownForHead: "Unknown node type $1 in ForStatement",
+  didYouMean: "Did you mean $1?",
+  codeGeneratorDeopt: "Note: The code generator has deoptimised the styling of $1 as it exceeds the max of $2.",
+  missingTemplatesDirectory: "no templates directory - this is most likely the result of a broken `npm publish`. Please report to https://github.com/babel/babel/issues",
+  unsupportedOutputType: "Unsupported output type $1",
+  illegalMethodName: "Illegal method name $1",
+  lostTrackNodePath: "We lost track of this node's position, likely because the AST was directly manipulated",
+
+  modulesIllegalExportName: "Illegal export $1",
+  modulesDuplicateDeclarations: "Duplicate module declarations with the same source but in different scopes",
+
+  undeclaredVariable: "Reference to undeclared variable $1",
+  undeclaredVariableType: "Referencing a type alias outside of a type annotation",
+  undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?",
+
+  traverseNeedsParent: "You must pass a scope and parentPath unless traversing a Program/File. Instead of that you tried to traverse a $1 node without passing scope and parentPath.",
+  traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?",
+  traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2",
+  traverseVerifyNodeType: "You gave us a visitor for the node type $1 but it's not a valid type",
+
+  pluginNotObject: "Plugin $2 specified in $1 was expected to return an object when invoked but returned $3",
+  pluginNotFunction: "Plugin $2 specified in $1 was expected to return a function but returned $3",
+  pluginUnknown: "Unknown plugin $1 specified in $2 at $3, attempted to resolve relative to $4",
+  pluginInvalidProperty: "Plugin $2 specified in $1 provided an invalid property of $3"
+};
+
+function get(key) {
+  for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+    args[_key - 1] = arguments[_key];
+  }
+
+  var msg = MESSAGES[key];
+  if (!msg) throw new ReferenceError("Unknown message " + (0, _stringify2.default)(key));
+
+  args = parseArgs(args);
+
+  return msg.replace(/\$(\d+)/g, function (str, i) {
+    return args[i - 1];
+  });
+}
+
+function parseArgs(args) {
+  return args.map(function (val) {
+    if (val != null && val.inspect) {
+      return val.inspect();
+    } else {
+      try {
+        return (0, _stringify2.default)(val) || val + "";
+      } catch (e) {
+        return util.inspect(val);
+      }
+    }
+  });
+}
+},{"babel-runtime/core-js/json/stringify":96,"util":560}],62:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (_ref) {
+  var messages = _ref.messages;
+
+  return {
+    visitor: {
+      Scope: function Scope(_ref2) {
+        var scope = _ref2.scope;
+
+        for (var name in scope.bindings) {
+          var binding = scope.bindings[name];
+          if (binding.kind !== "const" && binding.kind !== "module") continue;
+
+          for (var _iterator = binding.constantViolations, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+            var _ref3;
+
+            if (_isArray) {
+              if (_i >= _iterator.length) break;
+              _ref3 = _iterator[_i++];
+            } else {
+              _i = _iterator.next();
+              if (_i.done) break;
+              _ref3 = _i.value;
+            }
+
+            var violation = _ref3;
+
+            throw violation.buildCodeFrameError(messages.get("readOnly", name));
+          }
+        }
+      }
+    }
+  };
+};
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95}],63:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function () {
+  return {
+    manipulateOptions: function manipulateOptions(opts, parserOpts) {
+      parserOpts.plugins.push("dynamicImport");
+    }
+  };
+};
+
+module.exports = exports["default"];
+},{}],64:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  return {
+    visitor: {
+      ArrowFunctionExpression: function ArrowFunctionExpression(path, state) {
+        if (state.opts.spec) {
+          var node = path.node;
+
+          if (node.shadow) return;
+
+          node.shadow = { this: false };
+          node.type = "FunctionExpression";
+
+          var boundThis = t.thisExpression();
+          boundThis._forceShadow = path;
+
+          path.ensureBlock();
+          path.get("body").unshiftContainer("body", t.expressionStatement(t.callExpression(state.addHelper("newArrowCheck"), [t.thisExpression(), boundThis])));
+
+          path.replaceWith(t.callExpression(t.memberExpression(node, t.identifier("bind")), [t.thisExpression()]));
+        } else {
+          path.arrowFunctionToShadowed();
+        }
+      }
+    }
+  };
+};
+
+module.exports = exports["default"];
+},{}],65:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  function statementList(key, path) {
+    var paths = path.get(key);
+
+    for (var _iterator = paths, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref2;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref2 = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref2 = _i.value;
+      }
+
+      var _path = _ref2;
+
+      var func = _path.node;
+      if (!_path.isFunctionDeclaration()) continue;
+
+      var declar = t.variableDeclaration("let", [t.variableDeclarator(func.id, t.toExpression(func))]);
+
+      declar._blockHoist = 2;
+
+      func.id = null;
+
+      _path.replaceWith(declar);
+    }
+  }
+
+  return {
+    visitor: {
+      BlockStatement: function BlockStatement(path) {
+        var node = path.node,
+            parent = path.parent;
+
+        if (t.isFunction(parent, { body: node }) || t.isExportDeclaration(parent)) {
+          return;
+        }
+
+        statementList("body", path);
+      },
+      SwitchCase: function SwitchCase(path) {
+        statementList("consequent", path);
+      }
+    }
+  };
+};
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95}],66:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+var _create = require("babel-runtime/core-js/object/create");
+
+var _create2 = _interopRequireDefault(_create);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+exports.default = function () {
+  return {
+    visitor: {
+      VariableDeclaration: function VariableDeclaration(path, file) {
+        var node = path.node,
+            parent = path.parent,
+            scope = path.scope;
+
+        if (!isBlockScoped(node)) return;
+        convertBlockScopedToVar(path, null, parent, scope, true);
+
+        if (node._tdzThis) {
+          var nodes = [node];
+
+          for (var i = 0; i < node.declarations.length; i++) {
+            var decl = node.declarations[i];
+            if (decl.init) {
+              var assign = t.assignmentExpression("=", decl.id, decl.init);
+              assign._ignoreBlockScopingTDZ = true;
+              nodes.push(t.expressionStatement(assign));
+            }
+            decl.init = file.addHelper("temporalUndefined");
+          }
+
+          node._blockHoist = 2;
+
+          if (path.isCompletionRecord()) {
+            nodes.push(t.expressionStatement(scope.buildUndefinedNode()));
+          }
+
+          path.replaceWithMultiple(nodes);
+        }
+      },
+      Loop: function Loop(path, file) {
+        var node = path.node,
+            parent = path.parent,
+            scope = path.scope;
+
+        t.ensureBlock(node);
+        var blockScoping = new BlockScoping(path, path.get("body"), parent, scope, file);
+        var replace = blockScoping.run();
+        if (replace) path.replaceWith(replace);
+      },
+      CatchClause: function CatchClause(path, file) {
+        var parent = path.parent,
+            scope = path.scope;
+
+        var blockScoping = new BlockScoping(null, path.get("body"), parent, scope, file);
+        blockScoping.run();
+      },
+      "BlockStatement|SwitchStatement|Program": function BlockStatementSwitchStatementProgram(path, file) {
+        if (!ignoreBlock(path)) {
+          var blockScoping = new BlockScoping(null, path, path.parent, path.scope, file);
+          blockScoping.run();
+        }
+      }
+    }
+  };
+};
+
+var _babelTraverse = require("babel-traverse");
+
+var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
+
+var _tdz = require("./tdz");
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+var _values = require("lodash/values");
+
+var _values2 = _interopRequireDefault(_values);
+
+var _extend = require("lodash/extend");
+
+var _extend2 = _interopRequireDefault(_extend);
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function ignoreBlock(path) {
+  return t.isLoop(path.parent) || t.isCatchClause(path.parent);
+}
+
+var buildRetCheck = (0, _babelTemplate2.default)("\n  if (typeof RETURN === \"object\") return RETURN.v;\n");
+
+function isBlockScoped(node) {
+  if (!t.isVariableDeclaration(node)) return false;
+  if (node[t.BLOCK_SCOPED_SYMBOL]) return true;
+  if (node.kind !== "let" && node.kind !== "const") return false;
+  return true;
+}
+
+function convertBlockScopedToVar(path, node, parent, scope) {
+  var moveBindingsToParent = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
+
+  if (!node) {
+    node = path.node;
+  }
+
+  if (!t.isFor(parent)) {
+    for (var i = 0; i < node.declarations.length; i++) {
+      var declar = node.declarations[i];
+      declar.init = declar.init || scope.buildUndefinedNode();
+    }
+  }
+
+  node[t.BLOCK_SCOPED_SYMBOL] = true;
+  node.kind = "var";
+
+  if (moveBindingsToParent) {
+    var parentScope = scope.getFunctionParent();
+    var ids = path.getBindingIdentifiers();
+    for (var name in ids) {
+      var binding = scope.getOwnBinding(name);
+      if (binding) binding.kind = "var";
+      scope.moveBindingTo(name, parentScope);
+    }
+  }
+}
+
+function isVar(node) {
+  return t.isVariableDeclaration(node, { kind: "var" }) && !isBlockScoped(node);
+}
+
+var letReferenceBlockVisitor = _babelTraverse2.default.visitors.merge([{
+  Loop: {
+    enter: function enter(path, state) {
+      state.loopDepth++;
+    },
+    exit: function exit(path, state) {
+      state.loopDepth--;
+    }
+  },
+  Function: function Function(path, state) {
+    if (state.loopDepth > 0) {
+      path.traverse(letReferenceFunctionVisitor, state);
+    }
+    return path.skip();
+  }
+}, _tdz.visitor]);
+
+var letReferenceFunctionVisitor = _babelTraverse2.default.visitors.merge([{
+  ReferencedIdentifier: function ReferencedIdentifier(path, state) {
+    var ref = state.letReferences[path.node.name];
+
+    if (!ref) return;
+
+    var localBinding = path.scope.getBindingIdentifier(path.node.name);
+    if (localBinding && localBinding !== ref) return;
+
+    state.closurify = true;
+  }
+}, _tdz.visitor]);
+
+var hoistVarDeclarationsVisitor = {
+  enter: function enter(path, self) {
+    var node = path.node,
+        parent = path.parent;
+
+
+    if (path.isForStatement()) {
+      if (isVar(node.init, node)) {
+        var nodes = self.pushDeclar(node.init);
+        if (nodes.length === 1) {
+          node.init = nodes[0];
+        } else {
+          node.init = t.sequenceExpression(nodes);
+        }
+      }
+    } else if (path.isFor()) {
+      if (isVar(node.left, node)) {
+        self.pushDeclar(node.left);
+        node.left = node.left.declarations[0].id;
+      }
+    } else if (isVar(node, parent)) {
+      path.replaceWithMultiple(self.pushDeclar(node).map(function (expr) {
+        return t.expressionStatement(expr);
+      }));
+    } else if (path.isFunction()) {
+      return path.skip();
+    }
+  }
+};
+
+var loopLabelVisitor = {
+  LabeledStatement: function LabeledStatement(_ref, state) {
+    var node = _ref.node;
+
+    state.innerLabels.push(node.label.name);
+  }
+};
+
+var continuationVisitor = {
+  enter: function enter(path, state) {
+    if (path.isAssignmentExpression() || path.isUpdateExpression()) {
+      var bindings = path.getBindingIdentifiers();
+      for (var name in bindings) {
+        if (state.outsideReferences[name] !== path.scope.getBindingIdentifier(name)) continue;
+        state.reassignments[name] = true;
+      }
+    }
+  }
+};
+
+function loopNodeTo(node) {
+  if (t.isBreakStatement(node)) {
+    return "break";
+  } else if (t.isContinueStatement(node)) {
+    return "continue";
+  }
+}
+
+var loopVisitor = {
+  Loop: function Loop(path, state) {
+    var oldIgnoreLabeless = state.ignoreLabeless;
+    state.ignoreLabeless = true;
+    path.traverse(loopVisitor, state);
+    state.ignoreLabeless = oldIgnoreLabeless;
+    path.skip();
+  },
+  Function: function Function(path) {
+    path.skip();
+  },
+  SwitchCase: function SwitchCase(path, state) {
+    var oldInSwitchCase = state.inSwitchCase;
+    state.inSwitchCase = true;
+    path.traverse(loopVisitor, state);
+    state.inSwitchCase = oldInSwitchCase;
+    path.skip();
+  },
+  "BreakStatement|ContinueStatement|ReturnStatement": function BreakStatementContinueStatementReturnStatement(path, state) {
+    var node = path.node,
+        parent = path.parent,
+        scope = path.scope;
+
+    if (node[this.LOOP_IGNORE]) return;
+
+    var replace = void 0;
+    var loopText = loopNodeTo(node);
+
+    if (loopText) {
+      if (node.label) {
+        if (state.innerLabels.indexOf(node.label.name) >= 0) {
+          return;
+        }
+
+        loopText = loopText + "|" + node.label.name;
+      } else {
+        if (state.ignoreLabeless) return;
+
+        if (state.inSwitchCase) return;
+
+        if (t.isBreakStatement(node) && t.isSwitchCase(parent)) return;
+      }
+
+      state.hasBreakContinue = true;
+      state.map[loopText] = node;
+      replace = t.stringLiteral(loopText);
+    }
+
+    if (path.isReturnStatement()) {
+      state.hasReturn = true;
+      replace = t.objectExpression([t.objectProperty(t.identifier("v"), node.argument || scope.buildUndefinedNode())]);
+    }
+
+    if (replace) {
+      replace = t.returnStatement(replace);
+      replace[this.LOOP_IGNORE] = true;
+      path.skip();
+      path.replaceWith(t.inherits(replace, node));
+    }
+  }
+};
+
+var BlockScoping = function () {
+  function BlockScoping(loopPath, blockPath, parent, scope, file) {
+    (0, _classCallCheck3.default)(this, BlockScoping);
+
+    this.parent = parent;
+    this.scope = scope;
+    this.file = file;
+
+    this.blockPath = blockPath;
+    this.block = blockPath.node;
+
+    this.outsideLetReferences = (0, _create2.default)(null);
+    this.hasLetReferences = false;
+    this.letReferences = (0, _create2.default)(null);
+    this.body = [];
+
+    if (loopPath) {
+      this.loopParent = loopPath.parent;
+      this.loopLabel = t.isLabeledStatement(this.loopParent) && this.loopParent.label;
+      this.loopPath = loopPath;
+      this.loop = loopPath.node;
+    }
+  }
+
+  BlockScoping.prototype.run = function run() {
+    var block = this.block;
+    if (block._letDone) return;
+    block._letDone = true;
+
+    var needsClosure = this.getLetReferences();
+
+    if (t.isFunction(this.parent) || t.isProgram(this.block)) {
+      this.updateScopeInfo();
+      return;
+    }
+
+    if (!this.hasLetReferences) return;
+
+    if (needsClosure) {
+      this.wrapClosure();
+    } else {
+      this.remap();
+    }
+
+    this.updateScopeInfo(needsClosure);
+
+    if (this.loopLabel && !t.isLabeledStatement(this.loopParent)) {
+      return t.labeledStatement(this.loopLabel, this.loop);
+    }
+  };
+
+  BlockScoping.prototype.updateScopeInfo = function updateScopeInfo(wrappedInClosure) {
+    var scope = this.scope;
+    var parentScope = scope.getFunctionParent();
+    var letRefs = this.letReferences;
+
+    for (var key in letRefs) {
+      var ref = letRefs[key];
+      var binding = scope.getBinding(ref.name);
+      if (!binding) continue;
+      if (binding.kind === "let" || binding.kind === "const") {
+        binding.kind = "var";
+
+        if (wrappedInClosure) {
+          scope.removeBinding(ref.name);
+        } else {
+          scope.moveBindingTo(ref.name, parentScope);
+        }
+      }
+    }
+  };
+
+  BlockScoping.prototype.remap = function remap() {
+    var letRefs = this.letReferences;
+    var scope = this.scope;
+
+    for (var key in letRefs) {
+      var ref = letRefs[key];
+
+      if (scope.parentHasBinding(key) || scope.hasGlobal(key)) {
+        if (scope.hasOwnBinding(key)) scope.rename(ref.name);
+
+        if (this.blockPath.scope.hasOwnBinding(key)) this.blockPath.scope.rename(ref.name);
+      }
+    }
+  };
+
+  BlockScoping.prototype.wrapClosure = function wrapClosure() {
+    if (this.file.opts.throwIfClosureRequired) {
+      throw this.blockPath.buildCodeFrameError("Compiling let/const in this block would add a closure " + "(throwIfClosureRequired).");
+    }
+    var block = this.block;
+
+    var outsideRefs = this.outsideLetReferences;
+
+    if (this.loop) {
+      for (var name in outsideRefs) {
+        var id = outsideRefs[name];
+
+        if (this.scope.hasGlobal(id.name) || this.scope.parentHasBinding(id.name)) {
+          delete outsideRefs[id.name];
+          delete this.letReferences[id.name];
+
+          this.scope.rename(id.name);
+
+          this.letReferences[id.name] = id;
+          outsideRefs[id.name] = id;
+        }
+      }
+    }
+
+    this.has = this.checkLoop();
+
+    this.hoistVarDeclarations();
+
+    var params = (0, _values2.default)(outsideRefs);
+    var args = (0, _values2.default)(outsideRefs);
+
+    var isSwitch = this.blockPath.isSwitchStatement();
+
+    var fn = t.functionExpression(null, params, t.blockStatement(isSwitch ? [block] : block.body));
+    fn.shadow = true;
+
+    this.addContinuations(fn);
+
+    var ref = fn;
+
+    if (this.loop) {
+      ref = this.scope.generateUidIdentifier("loop");
+      this.loopPath.insertBefore(t.variableDeclaration("var", [t.variableDeclarator(ref, fn)]));
+    }
+
+    var call = t.callExpression(ref, args);
+    var ret = this.scope.generateUidIdentifier("ret");
+
+    var hasYield = _babelTraverse2.default.hasType(fn.body, this.scope, "YieldExpression", t.FUNCTION_TYPES);
+    if (hasYield) {
+      fn.generator = true;
+      call = t.yieldExpression(call, true);
+    }
+
+    var hasAsync = _babelTraverse2.default.hasType(fn.body, this.scope, "AwaitExpression", t.FUNCTION_TYPES);
+    if (hasAsync) {
+      fn.async = true;
+      call = t.awaitExpression(call);
+    }
+
+    this.buildClosure(ret, call);
+
+    if (isSwitch) this.blockPath.replaceWithMultiple(this.body);else block.body = this.body;
+  };
+
+  BlockScoping.prototype.buildClosure = function buildClosure(ret, call) {
+    var has = this.has;
+    if (has.hasReturn || has.hasBreakContinue) {
+      this.buildHas(ret, call);
+    } else {
+      this.body.push(t.expressionStatement(call));
+    }
+  };
+
+  BlockScoping.prototype.addContinuations = function addContinuations(fn) {
+    var state = {
+      reassignments: {},
+      outsideReferences: this.outsideLetReferences
+    };
+
+    this.scope.traverse(fn, continuationVisitor, state);
+
+    for (var i = 0; i < fn.params.length; i++) {
+      var param = fn.params[i];
+      if (!state.reassignments[param.name]) continue;
+
+      var newParam = this.scope.generateUidIdentifier(param.name);
+      fn.params[i] = newParam;
+
+      this.scope.rename(param.name, newParam.name, fn);
+
+      fn.body.body.push(t.expressionStatement(t.assignmentExpression("=", param, newParam)));
+    }
+  };
+
+  BlockScoping.prototype.getLetReferences = function getLetReferences() {
+    var _this = this;
+
+    var block = this.block;
+
+    var declarators = [];
+
+    if (this.loop) {
+      var init = this.loop.left || this.loop.init;
+      if (isBlockScoped(init)) {
+        declarators.push(init);
+        (0, _extend2.default)(this.outsideLetReferences, t.getBindingIdentifiers(init));
+      }
+    }
+
+    var addDeclarationsFromChild = function addDeclarationsFromChild(path, node) {
+      node = node || path.node;
+      if (t.isClassDeclaration(node) || t.isFunctionDeclaration(node) || isBlockScoped(node)) {
+        if (isBlockScoped(node)) {
+          convertBlockScopedToVar(path, node, block, _this.scope);
+        }
+        declarators = declarators.concat(node.declarations || node);
+      }
+      if (t.isLabeledStatement(node)) {
+        addDeclarationsFromChild(path.get("body"), node.body);
+      }
+    };
+
+    if (block.body) {
+      for (var i = 0; i < block.body.length; i++) {
+        var declarPath = this.blockPath.get("body")[i];
+        addDeclarationsFromChild(declarPath);
+      }
+    }
+
+    if (block.cases) {
+      for (var _i = 0; _i < block.cases.length; _i++) {
+        var consequents = block.cases[_i].consequent;
+
+        for (var j = 0; j < consequents.length; j++) {
+          var _declarPath = this.blockPath.get("cases")[_i];
+          var declar = consequents[j];
+          addDeclarationsFromChild(_declarPath, declar);
+        }
+      }
+    }
+
+    for (var _i2 = 0; _i2 < declarators.length; _i2++) {
+      var _declar = declarators[_i2];
+
+      var keys = t.getBindingIdentifiers(_declar, false, true);
+      (0, _extend2.default)(this.letReferences, keys);
+      this.hasLetReferences = true;
+    }
+
+    if (!this.hasLetReferences) return;
+
+    var state = {
+      letReferences: this.letReferences,
+      closurify: false,
+      file: this.file,
+      loopDepth: 0
+    };
+
+    var loopOrFunctionParent = this.blockPath.find(function (path) {
+      return path.isLoop() || path.isFunction();
+    });
+    if (loopOrFunctionParent && loopOrFunctionParent.isLoop()) {
+      state.loopDepth++;
+    }
+
+    this.blockPath.traverse(letReferenceBlockVisitor, state);
+
+    return state.closurify;
+  };
+
+  BlockScoping.prototype.checkLoop = function checkLoop() {
+    var state = {
+      hasBreakContinue: false,
+      ignoreLabeless: false,
+      inSwitchCase: false,
+      innerLabels: [],
+      hasReturn: false,
+      isLoop: !!this.loop,
+      map: {},
+      LOOP_IGNORE: (0, _symbol2.default)()
+    };
+
+    this.blockPath.traverse(loopLabelVisitor, state);
+    this.blockPath.traverse(loopVisitor, state);
+
+    return state;
+  };
+
+  BlockScoping.prototype.hoistVarDeclarations = function hoistVarDeclarations() {
+    this.blockPath.traverse(hoistVarDeclarationsVisitor, this);
+  };
+
+  BlockScoping.prototype.pushDeclar = function pushDeclar(node) {
+    var declars = [];
+    var names = t.getBindingIdentifiers(node);
+    for (var name in names) {
+      declars.push(t.variableDeclarator(names[name]));
+    }
+
+    this.body.push(t.variableDeclaration(node.kind, declars));
+
+    var replace = [];
+
+    for (var i = 0; i < node.declarations.length; i++) {
+      var declar = node.declarations[i];
+      if (!declar.init) continue;
+
+      var expr = t.assignmentExpression("=", declar.id, declar.init);
+      replace.push(t.inherits(expr, declar));
+    }
+
+    return replace;
+  };
+
+  BlockScoping.prototype.buildHas = function buildHas(ret, call) {
+    var body = this.body;
+
+    body.push(t.variableDeclaration("var", [t.variableDeclarator(ret, call)]));
+
+    var retCheck = void 0;
+    var has = this.has;
+    var cases = [];
+
+    if (has.hasReturn) {
+      retCheck = buildRetCheck({
+        RETURN: ret
+      });
+    }
+
+    if (has.hasBreakContinue) {
+      for (var key in has.map) {
+        cases.push(t.switchCase(t.stringLiteral(key), [has.map[key]]));
+      }
+
+      if (has.hasReturn) {
+        cases.push(t.switchCase(null, [retCheck]));
+      }
+
+      if (cases.length === 1) {
+        var single = cases[0];
+        body.push(t.ifStatement(t.binaryExpression("===", ret, single.test), single.consequent[0]));
+      } else {
+        if (this.loop) {
+          for (var i = 0; i < cases.length; i++) {
+            var caseConsequent = cases[i].consequent[0];
+            if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) {
+              caseConsequent.label = this.loopLabel = this.loopLabel || this.scope.generateUidIdentifier("loop");
+            }
+          }
+        }
+
+        body.push(t.switchStatement(ret, cases));
+      }
+    } else {
+      if (has.hasReturn) {
+        body.push(retCheck);
+      }
+    }
+  };
+
+  return BlockScoping;
+}();
+
+module.exports = exports["default"];
+},{"./tdz":67,"babel-runtime/core-js/object/create":100,"babel-runtime/core-js/symbol":104,"babel-runtime/helpers/classCallCheck":109,"babel-template":114,"babel-traverse":118,"babel-types":151,"lodash/extend":473,"lodash/values":518}],67:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.visitor = undefined;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function getTDZStatus(refPath, bindingPath) {
+  var executionStatus = bindingPath._guessExecutionStatusRelativeTo(refPath);
+
+  if (executionStatus === "before") {
+    return "inside";
+  } else if (executionStatus === "after") {
+    return "outside";
+  } else {
+    return "maybe";
+  }
+}
+
+function buildTDZAssert(node, file) {
+  return t.callExpression(file.addHelper("temporalRef"), [node, t.stringLiteral(node.name), file.addHelper("temporalUndefined")]);
+}
+
+function isReference(node, scope, state) {
+  var declared = state.letReferences[node.name];
+  if (!declared) return false;
+
+  return scope.getBindingIdentifier(node.name) === declared;
+}
+
+var visitor = exports.visitor = {
+  ReferencedIdentifier: function ReferencedIdentifier(path, state) {
+    if (!this.file.opts.tdz) return;
+
+    var node = path.node,
+        parent = path.parent,
+        scope = path.scope;
+
+
+    if (path.parentPath.isFor({ left: node })) return;
+    if (!isReference(node, scope, state)) return;
+
+    var bindingPath = scope.getBinding(node.name).path;
+
+    var status = getTDZStatus(path, bindingPath);
+    if (status === "inside") return;
+
+    if (status === "maybe") {
+      var assert = buildTDZAssert(node, state.file);
+
+      bindingPath.parent._tdzThis = true;
+
+      path.skip();
+
+      if (path.parentPath.isUpdateExpression()) {
+        if (parent._ignoreBlockScopingTDZ) return;
+        path.parentPath.replaceWith(t.sequenceExpression([assert, parent]));
+      } else {
+        path.replaceWith(assert);
+      }
+    } else if (status === "outside") {
+      path.replaceWith(t.throwStatement(t.inherits(t.newExpression(t.identifier("ReferenceError"), [t.stringLiteral(node.name + " is not defined - temporal dead zone")]), node)));
+    }
+  },
+
+
+  AssignmentExpression: {
+    exit: function exit(path, state) {
+      if (!this.file.opts.tdz) return;
+
+      var node = path.node;
+
+      if (node._ignoreBlockScopingTDZ) return;
+
+      var nodes = [];
+      var ids = path.getBindingIdentifiers();
+
+      for (var name in ids) {
+        var id = ids[name];
+
+        if (isReference(id, path.scope, state)) {
+          nodes.push(buildTDZAssert(id, state.file));
+        }
+      }
+
+      if (nodes.length) {
+        node._ignoreBlockScopingTDZ = true;
+        nodes.push(node);
+        path.replaceWithMultiple(nodes.map(t.expressionStatement));
+      }
+    }
+  }
+};
+},{"babel-types":151}],68:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  var VISITED = (0, _symbol2.default)();
+
+  return {
+    visitor: {
+      ExportDefaultDeclaration: function ExportDefaultDeclaration(path) {
+        if (!path.get("declaration").isClassDeclaration()) return;
+
+        var node = path.node;
+
+        var ref = node.declaration.id || path.scope.generateUidIdentifier("class");
+        node.declaration.id = ref;
+
+        path.replaceWith(node.declaration);
+        path.insertAfter(t.exportDefaultDeclaration(ref));
+      },
+      ClassDeclaration: function ClassDeclaration(path) {
+        var node = path.node;
+
+
+        var ref = node.id || path.scope.generateUidIdentifier("class");
+
+        path.replaceWith(t.variableDeclaration("let", [t.variableDeclarator(ref, t.toExpression(node))]));
+      },
+      ClassExpression: function ClassExpression(path, state) {
+        var node = path.node;
+
+        if (node[VISITED]) return;
+
+        var inferred = (0, _babelHelperFunctionName2.default)(path);
+        if (inferred && inferred !== node) return path.replaceWith(inferred);
+
+        node[VISITED] = true;
+
+        var Constructor = _vanilla2.default;
+        if (state.opts.loose) Constructor = _loose2.default;
+
+        path.replaceWith(new Constructor(path, state.file).run());
+      }
+    }
+  };
+};
+
+var _loose = require("./loose");
+
+var _loose2 = _interopRequireDefault(_loose);
+
+var _vanilla = require("./vanilla");
+
+var _vanilla2 = _interopRequireDefault(_vanilla);
+
+var _babelHelperFunctionName = require("babel-helper-function-name");
+
+var _babelHelperFunctionName2 = _interopRequireDefault(_babelHelperFunctionName);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"./loose":69,"./vanilla":70,"babel-helper-function-name":53,"babel-runtime/core-js/symbol":104}],69:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require("babel-runtime/helpers/inherits");
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _babelHelperFunctionName = require("babel-helper-function-name");
+
+var _babelHelperFunctionName2 = _interopRequireDefault(_babelHelperFunctionName);
+
+var _vanilla = require("./vanilla");
+
+var _vanilla2 = _interopRequireDefault(_vanilla);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var LooseClassTransformer = function (_VanillaTransformer) {
+  (0, _inherits3.default)(LooseClassTransformer, _VanillaTransformer);
+
+  function LooseClassTransformer() {
+    (0, _classCallCheck3.default)(this, LooseClassTransformer);
+
+    var _this = (0, _possibleConstructorReturn3.default)(this, _VanillaTransformer.apply(this, arguments));
+
+    _this.isLoose = true;
+    return _this;
+  }
+
+  LooseClassTransformer.prototype._processMethod = function _processMethod(node, scope) {
+    if (!node.decorators) {
+
+      var classRef = this.classRef;
+      if (!node.static) classRef = t.memberExpression(classRef, t.identifier("prototype"));
+      var methodName = t.memberExpression(classRef, node.key, node.computed || t.isLiteral(node.key));
+
+      var func = t.functionExpression(null, node.params, node.body, node.generator, node.async);
+      func.returnType = node.returnType;
+      var key = t.toComputedKey(node, node.key);
+      if (t.isStringLiteral(key)) {
+        func = (0, _babelHelperFunctionName2.default)({
+          node: func,
+          id: key,
+          scope: scope
+        });
+      }
+
+      var expr = t.expressionStatement(t.assignmentExpression("=", methodName, func));
+      t.inheritsComments(expr, node);
+      this.body.push(expr);
+      return true;
+    }
+  };
+
+  return LooseClassTransformer;
+}(_vanilla2.default);
+
+exports.default = LooseClassTransformer;
+module.exports = exports["default"];
+},{"./vanilla":70,"babel-helper-function-name":53,"babel-runtime/helpers/classCallCheck":109,"babel-runtime/helpers/inherits":110,"babel-runtime/helpers/possibleConstructorReturn":112,"babel-types":151}],70:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _babelTraverse = require("babel-traverse");
+
+var _babelHelperReplaceSupers = require("babel-helper-replace-supers");
+
+var _babelHelperReplaceSupers2 = _interopRequireDefault(_babelHelperReplaceSupers);
+
+var _babelHelperOptimiseCallExpression = require("babel-helper-optimise-call-expression");
+
+var _babelHelperOptimiseCallExpression2 = _interopRequireDefault(_babelHelperOptimiseCallExpression);
+
+var _babelHelperDefineMap = require("babel-helper-define-map");
+
+var defineMap = _interopRequireWildcard(_babelHelperDefineMap);
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildDerivedConstructor = (0, _babelTemplate2.default)("\n  (function () {\n    super(...arguments);\n  })\n");
+
+var noMethodVisitor = {
+  "FunctionExpression|FunctionDeclaration": function FunctionExpressionFunctionDeclaration(path) {
+    if (!path.is("shadow")) {
+      path.skip();
+    }
+  },
+  Method: function Method(path) {
+    path.skip();
+  }
+};
+
+var verifyConstructorVisitor = _babelTraverse.visitors.merge([noMethodVisitor, {
+  Super: function Super(path) {
+    if (this.isDerived && !this.hasBareSuper && !path.parentPath.isCallExpression({ callee: path.node })) {
+      throw path.buildCodeFrameError("'super.*' is not allowed before super()");
+    }
+  },
+
+
+  CallExpression: {
+    exit: function exit(path) {
+      if (path.get("callee").isSuper()) {
+        this.hasBareSuper = true;
+
+        if (!this.isDerived) {
+          throw path.buildCodeFrameError("super() is only allowed in a derived constructor");
+        }
+      }
+    }
+  },
+
+  ThisExpression: function ThisExpression(path) {
+    if (this.isDerived && !this.hasBareSuper) {
+      if (!path.inShadow("this")) {
+        throw path.buildCodeFrameError("'this' is not allowed before super()");
+      }
+    }
+  }
+}]);
+
+var findThisesVisitor = _babelTraverse.visitors.merge([noMethodVisitor, {
+  ThisExpression: function ThisExpression(path) {
+    this.superThises.push(path);
+  }
+}]);
+
+var ClassTransformer = function () {
+  function ClassTransformer(path, file) {
+    (0, _classCallCheck3.default)(this, ClassTransformer);
+
+    this.parent = path.parent;
+    this.scope = path.scope;
+    this.node = path.node;
+    this.path = path;
+    this.file = file;
+
+    this.clearDescriptors();
+
+    this.instancePropBody = [];
+    this.instancePropRefs = {};
+    this.staticPropBody = [];
+    this.body = [];
+
+    this.bareSuperAfter = [];
+    this.bareSupers = [];
+
+    this.pushedConstructor = false;
+    this.pushedInherits = false;
+    this.isLoose = false;
+
+    this.superThises = [];
+
+    this.classId = this.node.id;
+
+    this.classRef = this.node.id ? t.identifier(this.node.id.name) : this.scope.generateUidIdentifier("class");
+
+    this.superName = this.node.superClass || t.identifier("Function");
+    this.isDerived = !!this.node.superClass;
+  }
+
+  ClassTransformer.prototype.run = function run() {
+    var _this = this;
+
+    var superName = this.superName;
+    var file = this.file;
+    var body = this.body;
+
+    var constructorBody = this.constructorBody = t.blockStatement([]);
+    this.constructor = this.buildConstructor();
+
+    var closureParams = [];
+    var closureArgs = [];
+
+    if (this.isDerived) {
+      closureArgs.push(superName);
+
+      superName = this.scope.generateUidIdentifierBasedOnNode(superName);
+      closureParams.push(superName);
+
+      this.superName = superName;
+    }
+
+    this.buildBody();
+
+    constructorBody.body.unshift(t.expressionStatement(t.callExpression(file.addHelper("classCallCheck"), [t.thisExpression(), this.classRef])));
+
+    body = body.concat(this.staticPropBody.map(function (fn) {
+      return fn(_this.classRef);
+    }));
+
+    if (this.classId) {
+      if (body.length === 1) return t.toExpression(body[0]);
+    }
+
+    body.push(t.returnStatement(this.classRef));
+
+    var container = t.functionExpression(null, closureParams, t.blockStatement(body));
+    container.shadow = true;
+    return t.callExpression(container, closureArgs);
+  };
+
+  ClassTransformer.prototype.buildConstructor = function buildConstructor() {
+    var func = t.functionDeclaration(this.classRef, [], this.constructorBody);
+    t.inherits(func, this.node);
+    return func;
+  };
+
+  ClassTransformer.prototype.pushToMap = function pushToMap(node, enumerable) {
+    var kind = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "value";
+    var scope = arguments[3];
+
+    var mutatorMap = void 0;
+    if (node.static) {
+      this.hasStaticDescriptors = true;
+      mutatorMap = this.staticMutatorMap;
+    } else {
+      this.hasInstanceDescriptors = true;
+      mutatorMap = this.instanceMutatorMap;
+    }
+
+    var map = defineMap.push(mutatorMap, node, kind, this.file, scope);
+
+    if (enumerable) {
+      map.enumerable = t.booleanLiteral(true);
+    }
+
+    return map;
+  };
+
+  ClassTransformer.prototype.constructorMeMaybe = function constructorMeMaybe() {
+    var hasConstructor = false;
+    var paths = this.path.get("body.body");
+    for (var _iterator = paths, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var path = _ref;
+
+      hasConstructor = path.equals("kind", "constructor");
+      if (hasConstructor) break;
+    }
+    if (hasConstructor) return;
+
+    var params = void 0,
+        body = void 0;
+
+    if (this.isDerived) {
+      var _constructor = buildDerivedConstructor().expression;
+      params = _constructor.params;
+      body = _constructor.body;
+    } else {
+      params = [];
+      body = t.blockStatement([]);
+    }
+
+    this.path.get("body").unshiftContainer("body", t.classMethod("constructor", t.identifier("constructor"), params, body));
+  };
+
+  ClassTransformer.prototype.buildBody = function buildBody() {
+    this.constructorMeMaybe();
+    this.pushBody();
+    this.verifyConstructor();
+
+    if (this.userConstructor) {
+      var constructorBody = this.constructorBody;
+      constructorBody.body = constructorBody.body.concat(this.userConstructor.body.body);
+      t.inherits(this.constructor, this.userConstructor);
+      t.inherits(constructorBody, this.userConstructor.body);
+    }
+
+    this.pushDescriptors();
+  };
+
+  ClassTransformer.prototype.pushBody = function pushBody() {
+    var classBodyPaths = this.path.get("body.body");
+
+    for (var _iterator2 = classBodyPaths, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref2;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref2 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref2 = _i2.value;
+      }
+
+      var path = _ref2;
+
+      var node = path.node;
+
+      if (path.isClassProperty()) {
+        throw path.buildCodeFrameError("Missing class properties transform.");
+      }
+
+      if (node.decorators) {
+        throw path.buildCodeFrameError("Method has decorators, put the decorator plugin before the classes one.");
+      }
+
+      if (t.isClassMethod(node)) {
+        var isConstructor = node.kind === "constructor";
+
+        if (isConstructor) {
+          path.traverse(verifyConstructorVisitor, this);
+
+          if (!this.hasBareSuper && this.isDerived) {
+            throw path.buildCodeFrameError("missing super() call in constructor");
+          }
+        }
+
+        var replaceSupers = new _babelHelperReplaceSupers2.default({
+          forceSuperMemoisation: isConstructor,
+          methodPath: path,
+          methodNode: node,
+          objectRef: this.classRef,
+          superRef: this.superName,
+          isStatic: node.static,
+          isLoose: this.isLoose,
+          scope: this.scope,
+          file: this.file
+        }, true);
+
+        replaceSupers.replace();
+
+        if (isConstructor) {
+          this.pushConstructor(replaceSupers, node, path);
+        } else {
+          this.pushMethod(node, path);
+        }
+      }
+    }
+  };
+
+  ClassTransformer.prototype.clearDescriptors = function clearDescriptors() {
+    this.hasInstanceDescriptors = false;
+    this.hasStaticDescriptors = false;
+
+    this.instanceMutatorMap = {};
+    this.staticMutatorMap = {};
+  };
+
+  ClassTransformer.prototype.pushDescriptors = function pushDescriptors() {
+    this.pushInherits();
+
+    var body = this.body;
+
+    var instanceProps = void 0;
+    var staticProps = void 0;
+
+    if (this.hasInstanceDescriptors) {
+      instanceProps = defineMap.toClassObject(this.instanceMutatorMap);
+    }
+
+    if (this.hasStaticDescriptors) {
+      staticProps = defineMap.toClassObject(this.staticMutatorMap);
+    }
+
+    if (instanceProps || staticProps) {
+      if (instanceProps) instanceProps = defineMap.toComputedObjectFromClass(instanceProps);
+      if (staticProps) staticProps = defineMap.toComputedObjectFromClass(staticProps);
+
+      var nullNode = t.nullLiteral();
+
+      var args = [this.classRef, nullNode, nullNode, nullNode, nullNode];
+
+      if (instanceProps) args[1] = instanceProps;
+      if (staticProps) args[2] = staticProps;
+
+      if (this.instanceInitializersId) {
+        args[3] = this.instanceInitializersId;
+        body.unshift(this.buildObjectAssignment(this.instanceInitializersId));
+      }
+
+      if (this.staticInitializersId) {
+        args[4] = this.staticInitializersId;
+        body.unshift(this.buildObjectAssignment(this.staticInitializersId));
+      }
+
+      var lastNonNullIndex = 0;
+      for (var i = 0; i < args.length; i++) {
+        if (args[i] !== nullNode) lastNonNullIndex = i;
+      }
+      args = args.slice(0, lastNonNullIndex + 1);
+
+      body.push(t.expressionStatement(t.callExpression(this.file.addHelper("createClass"), args)));
+    }
+
+    this.clearDescriptors();
+  };
+
+  ClassTransformer.prototype.buildObjectAssignment = function buildObjectAssignment(id) {
+    return t.variableDeclaration("var", [t.variableDeclarator(id, t.objectExpression([]))]);
+  };
+
+  ClassTransformer.prototype.wrapSuperCall = function wrapSuperCall(bareSuper, superRef, thisRef, body) {
+    var bareSuperNode = bareSuper.node;
+
+    if (this.isLoose) {
+      bareSuperNode.arguments.unshift(t.thisExpression());
+      if (bareSuperNode.arguments.length === 2 && t.isSpreadElement(bareSuperNode.arguments[1]) && t.isIdentifier(bareSuperNode.arguments[1].argument, { name: "arguments" })) {
+        bareSuperNode.arguments[1] = bareSuperNode.arguments[1].argument;
+        bareSuperNode.callee = t.memberExpression(superRef, t.identifier("apply"));
+      } else {
+        bareSuperNode.callee = t.memberExpression(superRef, t.identifier("call"));
+      }
+    } else {
+      bareSuperNode = (0, _babelHelperOptimiseCallExpression2.default)(t.logicalExpression("||", t.memberExpression(this.classRef, t.identifier("__proto__")), t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")), [this.classRef])), t.thisExpression(), bareSuperNode.arguments);
+    }
+
+    var call = t.callExpression(this.file.addHelper("possibleConstructorReturn"), [t.thisExpression(), bareSuperNode]);
+
+    var bareSuperAfter = this.bareSuperAfter.map(function (fn) {
+      return fn(thisRef);
+    });
+
+    if (bareSuper.parentPath.isExpressionStatement() && bareSuper.parentPath.container === body.node.body && body.node.body.length - 1 === bareSuper.parentPath.key) {
+
+      if (this.superThises.length || bareSuperAfter.length) {
+        bareSuper.scope.push({ id: thisRef });
+        call = t.assignmentExpression("=", thisRef, call);
+      }
+
+      if (bareSuperAfter.length) {
+        call = t.toSequenceExpression([call].concat(bareSuperAfter, [thisRef]));
+      }
+
+      bareSuper.parentPath.replaceWith(t.returnStatement(call));
+    } else {
+      bareSuper.replaceWithMultiple([t.variableDeclaration("var", [t.variableDeclarator(thisRef, call)])].concat(bareSuperAfter, [t.expressionStatement(thisRef)]));
+    }
+  };
+
+  ClassTransformer.prototype.verifyConstructor = function verifyConstructor() {
+    var _this2 = this;
+
+    if (!this.isDerived) return;
+
+    var path = this.userConstructorPath;
+    var body = path.get("body");
+
+    path.traverse(findThisesVisitor, this);
+
+    var guaranteedSuperBeforeFinish = !!this.bareSupers.length;
+
+    var superRef = this.superName || t.identifier("Function");
+    var thisRef = path.scope.generateUidIdentifier("this");
+
+    for (var _iterator3 = this.bareSupers, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+      var _ref3;
+
+      if (_isArray3) {
+        if (_i3 >= _iterator3.length) break;
+        _ref3 = _iterator3[_i3++];
+      } else {
+        _i3 = _iterator3.next();
+        if (_i3.done) break;
+        _ref3 = _i3.value;
+      }
+
+      var bareSuper = _ref3;
+
+      this.wrapSuperCall(bareSuper, superRef, thisRef, body);
+
+      if (guaranteedSuperBeforeFinish) {
+        bareSuper.find(function (parentPath) {
+          if (parentPath === path) {
+            return true;
+          }
+
+          if (parentPath.isLoop() || parentPath.isConditional()) {
+            guaranteedSuperBeforeFinish = false;
+            return true;
+          }
+        });
+      }
+    }
+
+    for (var _iterator4 = this.superThises, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : (0, _getIterator3.default)(_iterator4);;) {
+      var _ref4;
+
+      if (_isArray4) {
+        if (_i4 >= _iterator4.length) break;
+        _ref4 = _iterator4[_i4++];
+      } else {
+        _i4 = _iterator4.next();
+        if (_i4.done) break;
+        _ref4 = _i4.value;
+      }
+
+      var thisPath = _ref4;
+
+      thisPath.replaceWith(thisRef);
+    }
+
+    var wrapReturn = function wrapReturn(returnArg) {
+      return t.callExpression(_this2.file.addHelper("possibleConstructorReturn"), [thisRef].concat(returnArg || []));
+    };
+
+    var bodyPaths = body.get("body");
+    if (bodyPaths.length && !bodyPaths.pop().isReturnStatement()) {
+      body.pushContainer("body", t.returnStatement(guaranteedSuperBeforeFinish ? thisRef : wrapReturn()));
+    }
+
+    for (var _iterator5 = this.superReturns, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : (0, _getIterator3.default)(_iterator5);;) {
+      var _ref5;
+
+      if (_isArray5) {
+        if (_i5 >= _iterator5.length) break;
+        _ref5 = _iterator5[_i5++];
+      } else {
+        _i5 = _iterator5.next();
+        if (_i5.done) break;
+        _ref5 = _i5.value;
+      }
+
+      var returnPath = _ref5;
+
+      if (returnPath.node.argument) {
+        var ref = returnPath.scope.generateDeclaredUidIdentifier("ret");
+        returnPath.get("argument").replaceWithMultiple([t.assignmentExpression("=", ref, returnPath.node.argument), wrapReturn(ref)]);
+      } else {
+        returnPath.get("argument").replaceWith(wrapReturn());
+      }
+    }
+  };
+
+  ClassTransformer.prototype.pushMethod = function pushMethod(node, path) {
+    var scope = path ? path.scope : this.scope;
+
+    if (node.kind === "method") {
+      if (this._processMethod(node, scope)) return;
+    }
+
+    this.pushToMap(node, false, null, scope);
+  };
+
+  ClassTransformer.prototype._processMethod = function _processMethod() {
+    return false;
+  };
+
+  ClassTransformer.prototype.pushConstructor = function pushConstructor(replaceSupers, method, path) {
+    this.bareSupers = replaceSupers.bareSupers;
+    this.superReturns = replaceSupers.returns;
+
+    if (path.scope.hasOwnBinding(this.classRef.name)) {
+      path.scope.rename(this.classRef.name);
+    }
+
+    var construct = this.constructor;
+
+    this.userConstructorPath = path;
+    this.userConstructor = method;
+    this.hasConstructor = true;
+
+    t.inheritsComments(construct, method);
+
+    construct._ignoreUserWhitespace = true;
+    construct.params = method.params;
+
+    t.inherits(construct.body, method.body);
+    construct.body.directives = method.body.directives;
+
+    this._pushConstructor();
+  };
+
+  ClassTransformer.prototype._pushConstructor = function _pushConstructor() {
+    if (this.pushedConstructor) return;
+    this.pushedConstructor = true;
+
+    if (this.hasInstanceDescriptors || this.hasStaticDescriptors) {
+      this.pushDescriptors();
+    }
+
+    this.body.push(this.constructor);
+
+    this.pushInherits();
+  };
+
+  ClassTransformer.prototype.pushInherits = function pushInherits() {
+    if (!this.isDerived || this.pushedInherits) return;
+
+    this.pushedInherits = true;
+    this.body.unshift(t.expressionStatement(t.callExpression(this.file.addHelper("inherits"), [this.classRef, this.superName])));
+  };
+
+  return ClassTransformer;
+}();
+
+exports.default = ClassTransformer;
+module.exports = exports["default"];
+},{"babel-helper-define-map":52,"babel-helper-optimise-call-expression":56,"babel-helper-replace-supers":58,"babel-runtime/core-js/get-iterator":95,"babel-runtime/helpers/classCallCheck":109,"babel-template":114,"babel-traverse":118,"babel-types":151}],71:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (_ref) {
+  var t = _ref.types,
+      template = _ref.template;
+
+  var buildMutatorMapAssign = template("\n    MUTATOR_MAP_REF[KEY] = MUTATOR_MAP_REF[KEY] || {};\n    MUTATOR_MAP_REF[KEY].KIND = VALUE;\n  ");
+
+  function getValue(prop) {
+    if (t.isObjectProperty(prop)) {
+      return prop.value;
+    } else if (t.isObjectMethod(prop)) {
+      return t.functionExpression(null, prop.params, prop.body, prop.generator, prop.async);
+    }
+  }
+
+  function pushAssign(objId, prop, body) {
+    if (prop.kind === "get" && prop.kind === "set") {
+      pushMutatorDefine(objId, prop, body);
+    } else {
+      body.push(t.expressionStatement(t.assignmentExpression("=", t.memberExpression(objId, prop.key, prop.computed || t.isLiteral(prop.key)), getValue(prop))));
+    }
+  }
+
+  function pushMutatorDefine(_ref2, prop) {
+    var objId = _ref2.objId,
+        body = _ref2.body,
+        getMutatorId = _ref2.getMutatorId,
+        scope = _ref2.scope;
+
+    var key = !prop.computed && t.isIdentifier(prop.key) ? t.stringLiteral(prop.key.name) : prop.key;
+
+    var maybeMemoise = scope.maybeGenerateMemoised(key);
+    if (maybeMemoise) {
+      body.push(t.expressionStatement(t.assignmentExpression("=", maybeMemoise, key)));
+      key = maybeMemoise;
+    }
+
+    body.push.apply(body, buildMutatorMapAssign({
+      MUTATOR_MAP_REF: getMutatorId(),
+      KEY: key,
+      VALUE: getValue(prop),
+      KIND: t.identifier(prop.kind)
+    }));
+  }
+
+  function loose(info) {
+    for (var _iterator = info.computedProps, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref3;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref3 = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref3 = _i.value;
+      }
+
+      var prop = _ref3;
+
+      if (prop.kind === "get" || prop.kind === "set") {
+        pushMutatorDefine(info, prop);
+      } else {
+        pushAssign(info.objId, prop, info.body);
+      }
+    }
+  }
+
+  function spec(info) {
+    var objId = info.objId,
+        body = info.body,
+        computedProps = info.computedProps,
+        state = info.state;
+
+
+    for (var _iterator2 = computedProps, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref4;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref4 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref4 = _i2.value;
+      }
+
+      var prop = _ref4;
+
+      var key = t.toComputedKey(prop);
+
+      if (prop.kind === "get" || prop.kind === "set") {
+        pushMutatorDefine(info, prop);
+      } else if (t.isStringLiteral(key, { value: "__proto__" })) {
+        pushAssign(objId, prop, body);
+      } else {
+        if (computedProps.length === 1) {
+          return t.callExpression(state.addHelper("defineProperty"), [info.initPropExpression, key, getValue(prop)]);
+        } else {
+          body.push(t.expressionStatement(t.callExpression(state.addHelper("defineProperty"), [objId, key, getValue(prop)])));
+        }
+      }
+    }
+  }
+
+  return {
+    visitor: {
+      ObjectExpression: {
+        exit: function exit(path, state) {
+          var node = path.node,
+              parent = path.parent,
+              scope = path.scope;
+
+          var hasComputed = false;
+          for (var _iterator3 = node.properties, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+            var _ref5;
+
+            if (_isArray3) {
+              if (_i3 >= _iterator3.length) break;
+              _ref5 = _iterator3[_i3++];
+            } else {
+              _i3 = _iterator3.next();
+              if (_i3.done) break;
+              _ref5 = _i3.value;
+            }
+
+            var prop = _ref5;
+
+            hasComputed = prop.computed === true;
+            if (hasComputed) break;
+          }
+          if (!hasComputed) return;
+
+          var initProps = [];
+          var computedProps = [];
+          var foundComputed = false;
+
+          for (var _iterator4 = node.properties, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : (0, _getIterator3.default)(_iterator4);;) {
+            var _ref6;
+
+            if (_isArray4) {
+              if (_i4 >= _iterator4.length) break;
+              _ref6 = _iterator4[_i4++];
+            } else {
+              _i4 = _iterator4.next();
+              if (_i4.done) break;
+              _ref6 = _i4.value;
+            }
+
+            var _prop = _ref6;
+
+            if (_prop.computed) {
+              foundComputed = true;
+            }
+
+            if (foundComputed) {
+              computedProps.push(_prop);
+            } else {
+              initProps.push(_prop);
+            }
+          }
+
+          var objId = scope.generateUidIdentifierBasedOnNode(parent);
+          var initPropExpression = t.objectExpression(initProps);
+          var body = [];
+
+          body.push(t.variableDeclaration("var", [t.variableDeclarator(objId, initPropExpression)]));
+
+          var callback = spec;
+          if (state.opts.loose) callback = loose;
+
+          var mutatorRef = void 0;
+
+          var getMutatorId = function getMutatorId() {
+            if (!mutatorRef) {
+              mutatorRef = scope.generateUidIdentifier("mutatorMap");
+
+              body.push(t.variableDeclaration("var", [t.variableDeclarator(mutatorRef, t.objectExpression([]))]));
+            }
+
+            return mutatorRef;
+          };
+
+          var single = callback({
+            scope: scope,
+            objId: objId,
+            body: body,
+            computedProps: computedProps,
+            initPropExpression: initPropExpression,
+            getMutatorId: getMutatorId,
+            state: state
+          });
+
+          if (mutatorRef) {
+            body.push(t.expressionStatement(t.callExpression(state.addHelper("defineEnumerableProperties"), [objId, mutatorRef])));
+          }
+
+          if (single) {
+            path.replaceWith(single);
+          } else {
+            body.push(t.expressionStatement(objId));
+            path.replaceWithMultiple(body);
+          }
+        }
+      }
+    }
+  };
+};
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95}],72:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+
+  function variableDeclarationHasPattern(node) {
+    for (var _iterator = node.declarations, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref2;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref2 = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref2 = _i.value;
+      }
+
+      var declar = _ref2;
+
+      if (t.isPattern(declar.id)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  function hasRest(pattern) {
+    for (var _iterator2 = pattern.elements, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref3;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref3 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref3 = _i2.value;
+      }
+
+      var elem = _ref3;
+
+      if (t.isRestElement(elem)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  var arrayUnpackVisitor = {
+    ReferencedIdentifier: function ReferencedIdentifier(path, state) {
+      if (state.bindings[path.node.name]) {
+        state.deopt = true;
+        path.stop();
+      }
+    }
+  };
+
+  var DestructuringTransformer = function () {
+    function DestructuringTransformer(opts) {
+      (0, _classCallCheck3.default)(this, DestructuringTransformer);
+
+      this.blockHoist = opts.blockHoist;
+      this.operator = opts.operator;
+      this.arrays = {};
+      this.nodes = opts.nodes || [];
+      this.scope = opts.scope;
+      this.file = opts.file;
+      this.kind = opts.kind;
+    }
+
+    DestructuringTransformer.prototype.buildVariableAssignment = function buildVariableAssignment(id, init) {
+      var op = this.operator;
+      if (t.isMemberExpression(id)) op = "=";
+
+      var node = void 0;
+
+      if (op) {
+        node = t.expressionStatement(t.assignmentExpression(op, id, init));
+      } else {
+        node = t.variableDeclaration(this.kind, [t.variableDeclarator(id, init)]);
+      }
+
+      node._blockHoist = this.blockHoist;
+
+      return node;
+    };
+
+    DestructuringTransformer.prototype.buildVariableDeclaration = function buildVariableDeclaration(id, init) {
+      var declar = t.variableDeclaration("var", [t.variableDeclarator(id, init)]);
+      declar._blockHoist = this.blockHoist;
+      return declar;
+    };
+
+    DestructuringTransformer.prototype.push = function push(id, init) {
+      if (t.isObjectPattern(id)) {
+        this.pushObjectPattern(id, init);
+      } else if (t.isArrayPattern(id)) {
+        this.pushArrayPattern(id, init);
+      } else if (t.isAssignmentPattern(id)) {
+        this.pushAssignmentPattern(id, init);
+      } else {
+        this.nodes.push(this.buildVariableAssignment(id, init));
+      }
+    };
+
+    DestructuringTransformer.prototype.toArray = function toArray(node, count) {
+      if (this.file.opts.loose || t.isIdentifier(node) && this.arrays[node.name]) {
+        return node;
+      } else {
+        return this.scope.toArray(node, count);
+      }
+    };
+
+    DestructuringTransformer.prototype.pushAssignmentPattern = function pushAssignmentPattern(pattern, valueRef) {
+
+      var tempValueRef = this.scope.generateUidIdentifierBasedOnNode(valueRef);
+
+      var declar = t.variableDeclaration("var", [t.variableDeclarator(tempValueRef, valueRef)]);
+      declar._blockHoist = this.blockHoist;
+      this.nodes.push(declar);
+
+      var tempConditional = t.conditionalExpression(t.binaryExpression("===", tempValueRef, t.identifier("undefined")), pattern.right, tempValueRef);
+
+      var left = pattern.left;
+      if (t.isPattern(left)) {
+        var tempValueDefault = t.expressionStatement(t.assignmentExpression("=", tempValueRef, tempConditional));
+        tempValueDefault._blockHoist = this.blockHoist;
+
+        this.nodes.push(tempValueDefault);
+        this.push(left, tempValueRef);
+      } else {
+        this.nodes.push(this.buildVariableAssignment(left, tempConditional));
+      }
+    };
+
+    DestructuringTransformer.prototype.pushObjectRest = function pushObjectRest(pattern, objRef, spreadProp, spreadPropIndex) {
+
+      var keys = [];
+
+      for (var i = 0; i < pattern.properties.length; i++) {
+        var prop = pattern.properties[i];
+
+        if (i >= spreadPropIndex) break;
+
+        if (t.isRestProperty(prop)) continue;
+
+        var key = prop.key;
+        if (t.isIdentifier(key) && !prop.computed) key = t.stringLiteral(prop.key.name);
+        keys.push(key);
+      }
+
+      keys = t.arrayExpression(keys);
+
+      var value = t.callExpression(this.file.addHelper("objectWithoutProperties"), [objRef, keys]);
+      this.nodes.push(this.buildVariableAssignment(spreadProp.argument, value));
+    };
+
+    DestructuringTransformer.prototype.pushObjectProperty = function pushObjectProperty(prop, propRef) {
+      if (t.isLiteral(prop.key)) prop.computed = true;
+
+      var pattern = prop.value;
+      var objRef = t.memberExpression(propRef, prop.key, prop.computed);
+
+      if (t.isPattern(pattern)) {
+        this.push(pattern, objRef);
+      } else {
+        this.nodes.push(this.buildVariableAssignment(pattern, objRef));
+      }
+    };
+
+    DestructuringTransformer.prototype.pushObjectPattern = function pushObjectPattern(pattern, objRef) {
+
+      if (!pattern.properties.length) {
+        this.nodes.push(t.expressionStatement(t.callExpression(this.file.addHelper("objectDestructuringEmpty"), [objRef])));
+      }
+
+      if (pattern.properties.length > 1 && !this.scope.isStatic(objRef)) {
+        var temp = this.scope.generateUidIdentifierBasedOnNode(objRef);
+        this.nodes.push(this.buildVariableDeclaration(temp, objRef));
+        objRef = temp;
+      }
+
+      for (var i = 0; i < pattern.properties.length; i++) {
+        var prop = pattern.properties[i];
+        if (t.isRestProperty(prop)) {
+          this.pushObjectRest(pattern, objRef, prop, i);
+        } else {
+          this.pushObjectProperty(prop, objRef);
+        }
+      }
+    };
+
+    DestructuringTransformer.prototype.canUnpackArrayPattern = function canUnpackArrayPattern(pattern, arr) {
+      if (!t.isArrayExpression(arr)) return false;
+
+      if (pattern.elements.length > arr.elements.length) return;
+      if (pattern.elements.length < arr.elements.length && !hasRest(pattern)) return false;
+
+      for (var _iterator3 = pattern.elements, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+        var _ref4;
+
+        if (_isArray3) {
+          if (_i3 >= _iterator3.length) break;
+          _ref4 = _iterator3[_i3++];
+        } else {
+          _i3 = _iterator3.next();
+          if (_i3.done) break;
+          _ref4 = _i3.value;
+        }
+
+        var elem = _ref4;
+
+        if (!elem) return false;
+
+        if (t.isMemberExpression(elem)) return false;
+      }
+
+      for (var _iterator4 = arr.elements, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : (0, _getIterator3.default)(_iterator4);;) {
+        var _ref5;
+
+        if (_isArray4) {
+          if (_i4 >= _iterator4.length) break;
+          _ref5 = _iterator4[_i4++];
+        } else {
+          _i4 = _iterator4.next();
+          if (_i4.done) break;
+          _ref5 = _i4.value;
+        }
+
+        var _elem = _ref5;
+
+        if (t.isSpreadElement(_elem)) return false;
+
+        if (t.isCallExpression(_elem)) return false;
+
+        if (t.isMemberExpression(_elem)) return false;
+      }
+
+      var bindings = t.getBindingIdentifiers(pattern);
+      var state = { deopt: false, bindings: bindings };
+      this.scope.traverse(arr, arrayUnpackVisitor, state);
+      return !state.deopt;
+    };
+
+    DestructuringTransformer.prototype.pushUnpackedArrayPattern = function pushUnpackedArrayPattern(pattern, arr) {
+      for (var i = 0; i < pattern.elements.length; i++) {
+        var elem = pattern.elements[i];
+        if (t.isRestElement(elem)) {
+          this.push(elem.argument, t.arrayExpression(arr.elements.slice(i)));
+        } else {
+          this.push(elem, arr.elements[i]);
+        }
+      }
+    };
+
+    DestructuringTransformer.prototype.pushArrayPattern = function pushArrayPattern(pattern, arrayRef) {
+      if (!pattern.elements) return;
+
+      if (this.canUnpackArrayPattern(pattern, arrayRef)) {
+        return this.pushUnpackedArrayPattern(pattern, arrayRef);
+      }
+
+      var count = !hasRest(pattern) && pattern.elements.length;
+
+      var toArray = this.toArray(arrayRef, count);
+
+      if (t.isIdentifier(toArray)) {
+        arrayRef = toArray;
+      } else {
+        arrayRef = this.scope.generateUidIdentifierBasedOnNode(arrayRef);
+        this.arrays[arrayRef.name] = true;
+        this.nodes.push(this.buildVariableDeclaration(arrayRef, toArray));
+      }
+
+      for (var i = 0; i < pattern.elements.length; i++) {
+        var elem = pattern.elements[i];
+
+        if (!elem) continue;
+
+        var elemRef = void 0;
+
+        if (t.isRestElement(elem)) {
+          elemRef = this.toArray(arrayRef);
+          elemRef = t.callExpression(t.memberExpression(elemRef, t.identifier("slice")), [t.numericLiteral(i)]);
+
+          elem = elem.argument;
+        } else {
+          elemRef = t.memberExpression(arrayRef, t.numericLiteral(i), true);
+        }
+
+        this.push(elem, elemRef);
+      }
+    };
+
+    DestructuringTransformer.prototype.init = function init(pattern, ref) {
+
+      if (!t.isArrayExpression(ref) && !t.isMemberExpression(ref)) {
+        var memo = this.scope.maybeGenerateMemoised(ref, true);
+        if (memo) {
+          this.nodes.push(this.buildVariableDeclaration(memo, ref));
+          ref = memo;
+        }
+      }
+
+      this.push(pattern, ref);
+
+      return this.nodes;
+    };
+
+    return DestructuringTransformer;
+  }();
+
+  return {
+    visitor: {
+      ExportNamedDeclaration: function ExportNamedDeclaration(path) {
+        var declaration = path.get("declaration");
+        if (!declaration.isVariableDeclaration()) return;
+        if (!variableDeclarationHasPattern(declaration.node)) return;
+
+        var specifiers = [];
+
+        for (var name in path.getOuterBindingIdentifiers(path)) {
+          var id = t.identifier(name);
+          specifiers.push(t.exportSpecifier(id, id));
+        }
+
+        path.replaceWith(declaration.node);
+        path.insertAfter(t.exportNamedDeclaration(null, specifiers));
+      },
+      ForXStatement: function ForXStatement(path, file) {
+        var node = path.node,
+            scope = path.scope;
+
+        var left = node.left;
+
+        if (t.isPattern(left)) {
+
+          var temp = scope.generateUidIdentifier("ref");
+
+          node.left = t.variableDeclaration("var", [t.variableDeclarator(temp)]);
+
+          path.ensureBlock();
+
+          node.body.body.unshift(t.variableDeclaration("var", [t.variableDeclarator(left, temp)]));
+
+          return;
+        }
+
+        if (!t.isVariableDeclaration(left)) return;
+
+        var pattern = left.declarations[0].id;
+        if (!t.isPattern(pattern)) return;
+
+        var key = scope.generateUidIdentifier("ref");
+        node.left = t.variableDeclaration(left.kind, [t.variableDeclarator(key, null)]);
+
+        var nodes = [];
+
+        var destructuring = new DestructuringTransformer({
+          kind: left.kind,
+          file: file,
+          scope: scope,
+          nodes: nodes
+        });
+
+        destructuring.init(pattern, key);
+
+        path.ensureBlock();
+
+        var block = node.body;
+        block.body = nodes.concat(block.body);
+      },
+      CatchClause: function CatchClause(_ref6, file) {
+        var node = _ref6.node,
+            scope = _ref6.scope;
+
+        var pattern = node.param;
+        if (!t.isPattern(pattern)) return;
+
+        var ref = scope.generateUidIdentifier("ref");
+        node.param = ref;
+
+        var nodes = [];
+
+        var destructuring = new DestructuringTransformer({
+          kind: "let",
+          file: file,
+          scope: scope,
+          nodes: nodes
+        });
+        destructuring.init(pattern, ref);
+
+        node.body.body = nodes.concat(node.body.body);
+      },
+      AssignmentExpression: function AssignmentExpression(path, file) {
+        var node = path.node,
+            scope = path.scope;
+
+        if (!t.isPattern(node.left)) return;
+
+        var nodes = [];
+
+        var destructuring = new DestructuringTransformer({
+          operator: node.operator,
+          file: file,
+          scope: scope,
+          nodes: nodes
+        });
+
+        var ref = void 0;
+        if (path.isCompletionRecord() || !path.parentPath.isExpressionStatement()) {
+          ref = scope.generateUidIdentifierBasedOnNode(node.right, "ref");
+
+          nodes.push(t.variableDeclaration("var", [t.variableDeclarator(ref, node.right)]));
+
+          if (t.isArrayExpression(node.right)) {
+            destructuring.arrays[ref.name] = true;
+          }
+        }
+
+        destructuring.init(node.left, ref || node.right);
+
+        if (ref) {
+          nodes.push(t.expressionStatement(ref));
+        }
+
+        path.replaceWithMultiple(nodes);
+      },
+      VariableDeclaration: function VariableDeclaration(path, file) {
+        var node = path.node,
+            scope = path.scope,
+            parent = path.parent;
+
+        if (t.isForXStatement(parent)) return;
+        if (!parent || !path.container) return;
+        if (!variableDeclarationHasPattern(node)) return;
+
+        var nodes = [];
+        var declar = void 0;
+
+        for (var i = 0; i < node.declarations.length; i++) {
+          declar = node.declarations[i];
+
+          var patternId = declar.init;
+          var pattern = declar.id;
+
+          var destructuring = new DestructuringTransformer({
+            blockHoist: node._blockHoist,
+            nodes: nodes,
+            scope: scope,
+            kind: node.kind,
+            file: file
+          });
+
+          if (t.isPattern(pattern)) {
+            destructuring.init(pattern, patternId);
+
+            if (+i !== node.declarations.length - 1) {
+              t.inherits(nodes[nodes.length - 1], declar);
+            }
+          } else {
+            nodes.push(t.inherits(destructuring.buildVariableAssignment(declar.id, declar.init), declar));
+          }
+        }
+
+        var nodesOut = [];
+        for (var _iterator5 = nodes, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : (0, _getIterator3.default)(_iterator5);;) {
+          var _ref7;
+
+          if (_isArray5) {
+            if (_i5 >= _iterator5.length) break;
+            _ref7 = _iterator5[_i5++];
+          } else {
+            _i5 = _iterator5.next();
+            if (_i5.done) break;
+            _ref7 = _i5.value;
+          }
+
+          var _node = _ref7;
+
+          var tail = nodesOut[nodesOut.length - 1];
+          if (tail && t.isVariableDeclaration(tail) && t.isVariableDeclaration(_node) && tail.kind === _node.kind) {
+            var _tail$declarations;
+
+            (_tail$declarations = tail.declarations).push.apply(_tail$declarations, _node.declarations);
+          } else {
+            nodesOut.push(_node);
+          }
+        }
+
+        for (var _iterator6 = nodesOut, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : (0, _getIterator3.default)(_iterator6);;) {
+          var _ref8;
+
+          if (_isArray6) {
+            if (_i6 >= _iterator6.length) break;
+            _ref8 = _iterator6[_i6++];
+          } else {
+            _i6 = _iterator6.next();
+            if (_i6.done) break;
+            _ref8 = _i6.value;
+          }
+
+          var nodeOut = _ref8;
+
+          if (!nodeOut.declarations) continue;
+          for (var _iterator7 = nodeOut.declarations, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : (0, _getIterator3.default)(_iterator7);;) {
+            var _ref9;
+
+            if (_isArray7) {
+              if (_i7 >= _iterator7.length) break;
+              _ref9 = _iterator7[_i7++];
+            } else {
+              _i7 = _iterator7.next();
+              if (_i7.done) break;
+              _ref9 = _i7.value;
+            }
+
+            var declaration = _ref9;
+            var name = declaration.id.name;
+
+            if (scope.bindings[name]) {
+              scope.bindings[name].kind = nodeOut.kind;
+            }
+          }
+        }
+
+        if (nodesOut.length === 1) {
+          path.replaceWith(nodesOut[0]);
+        } else {
+          path.replaceWithMultiple(nodesOut);
+        }
+      }
+    }
+  };
+};
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95,"babel-runtime/helpers/classCallCheck":109}],73:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _create = require("babel-runtime/core-js/object/create");
+
+var _create2 = _interopRequireDefault(_create);
+
+exports.default = function () {
+  return {
+    visitor: {
+      ObjectExpression: function ObjectExpression(path) {
+        var node = path.node;
+
+        var plainProps = node.properties.filter(function (prop) {
+          return !t.isSpreadProperty(prop) && !prop.computed;
+        });
+
+        var alreadySeenData = (0, _create2.default)(null);
+        var alreadySeenGetters = (0, _create2.default)(null);
+        var alreadySeenSetters = (0, _create2.default)(null);
+
+        for (var _iterator = plainProps, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+          var _ref;
+
+          if (_isArray) {
+            if (_i >= _iterator.length) break;
+            _ref = _iterator[_i++];
+          } else {
+            _i = _iterator.next();
+            if (_i.done) break;
+            _ref = _i.value;
+          }
+
+          var prop = _ref;
+
+          var name = getName(prop.key);
+          var isDuplicate = false;
+          switch (prop.kind) {
+            case "get":
+              if (alreadySeenData[name] || alreadySeenGetters[name]) {
+                isDuplicate = true;
+              }
+              alreadySeenGetters[name] = true;
+              break;
+            case "set":
+              if (alreadySeenData[name] || alreadySeenSetters[name]) {
+                isDuplicate = true;
+              }
+              alreadySeenSetters[name] = true;
+              break;
+            default:
+              if (alreadySeenData[name] || alreadySeenGetters[name] || alreadySeenSetters[name]) {
+                isDuplicate = true;
+              }
+              alreadySeenData[name] = true;
+          }
+
+          if (isDuplicate) {
+            prop.computed = true;
+            prop.key = t.stringLiteral(name);
+          }
+        }
+      }
+    }
+  };
+};
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function getName(key) {
+  if (t.isIdentifier(key)) {
+    return key.name;
+  }
+  return key.value.toString();
+}
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/object/create":100,"babel-types":151}],74:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (_ref) {
+  var messages = _ref.messages,
+      template = _ref.template,
+      t = _ref.types;
+
+  var buildForOfArray = template("\n    for (var KEY = 0; KEY < ARR.length; KEY++) BODY;\n  ");
+
+  var buildForOfLoose = template("\n    for (var LOOP_OBJECT = OBJECT,\n             IS_ARRAY = Array.isArray(LOOP_OBJECT),\n             INDEX = 0,\n             LOOP_OBJECT = IS_ARRAY ? LOOP_OBJECT : LOOP_OBJECT[Symbol.iterator]();;) {\n      var ID;\n      if (IS_ARRAY) {\n        if (INDEX >= LOOP_OBJECT.length) break;\n        ID = LOOP_OBJECT[INDEX++];\n      } else {\n        INDEX = LOOP_OBJECT.next();\n        if (INDEX.done) break;\n        ID = INDEX.value;\n      }\n    }\n  ");
+
+  var buildForOf = template("\n    var ITERATOR_COMPLETION = true;\n    var ITERATOR_HAD_ERROR_KEY = false;\n    var ITERATOR_ERROR_KEY = undefined;\n    try {\n      for (var ITERATOR_KEY = OBJECT[Symbol.iterator](), STEP_KEY; !(ITERATOR_COMPLETION = (STEP_KEY = ITERATOR_KEY.next()).done); ITERATOR_COMPLETION = true) {\n      }\n    } catch (err) {\n      ITERATOR_HAD_ERROR_KEY = true;\n      ITERATOR_ERROR_KEY = err;\n    } finally {\n      try {\n        if (!ITERATOR_COMPLETION && ITERATOR_KEY.return) {\n          ITERATOR_KEY.return();\n        }\n      } finally {\n        if (ITERATOR_HAD_ERROR_KEY) {\n          throw ITERATOR_ERROR_KEY;\n        }\n      }\n    }\n  ");
+
+
+  function _ForOfStatementArray(path) {
+    var node = path.node,
+        scope = path.scope;
+
+    var nodes = [];
+    var right = node.right;
+
+    if (!t.isIdentifier(right) || !scope.hasBinding(right.name)) {
+      var uid = scope.generateUidIdentifier("arr");
+      nodes.push(t.variableDeclaration("var", [t.variableDeclarator(uid, right)]));
+      right = uid;
+    }
+
+    var iterationKey = scope.generateUidIdentifier("i");
+
+    var loop = buildForOfArray({
+      BODY: node.body,
+      KEY: iterationKey,
+      ARR: right
+    });
+
+    t.inherits(loop, node);
+    t.ensureBlock(loop);
+
+    var iterationValue = t.memberExpression(right, iterationKey, true);
+
+    var left = node.left;
+    if (t.isVariableDeclaration(left)) {
+      left.declarations[0].init = iterationValue;
+      loop.body.body.unshift(left);
+    } else {
+      loop.body.body.unshift(t.expressionStatement(t.assignmentExpression("=", left, iterationValue)));
+    }
+
+    if (path.parentPath.isLabeledStatement()) {
+      loop = t.labeledStatement(path.parentPath.node.label, loop);
+    }
+
+    nodes.push(loop);
+
+    return nodes;
+  }
+
+  return {
+    visitor: {
+      ForOfStatement: function ForOfStatement(path, state) {
+        if (path.get("right").isArrayExpression()) {
+          if (path.parentPath.isLabeledStatement()) {
+            return path.parentPath.replaceWithMultiple(_ForOfStatementArray(path));
+          } else {
+            return path.replaceWithMultiple(_ForOfStatementArray(path));
+          }
+        }
+
+        var callback = spec;
+        if (state.opts.loose) callback = loose;
+
+        var node = path.node;
+
+        var build = callback(path, state);
+        var declar = build.declar;
+        var loop = build.loop;
+        var block = loop.body;
+
+        path.ensureBlock();
+
+        if (declar) {
+          block.body.push(declar);
+        }
+
+        block.body = block.body.concat(node.body.body);
+
+        t.inherits(loop, node);
+        t.inherits(loop.body, node.body);
+
+        if (build.replaceParent) {
+          path.parentPath.replaceWithMultiple(build.node);
+          path.remove();
+        } else {
+          path.replaceWithMultiple(build.node);
+        }
+      }
+    }
+  };
+
+  function loose(path, file) {
+    var node = path.node,
+        scope = path.scope,
+        parent = path.parent;
+    var left = node.left;
+
+    var declar = void 0,
+        id = void 0;
+
+    if (t.isIdentifier(left) || t.isPattern(left) || t.isMemberExpression(left)) {
+      id = left;
+    } else if (t.isVariableDeclaration(left)) {
+      id = scope.generateUidIdentifier("ref");
+      declar = t.variableDeclaration(left.kind, [t.variableDeclarator(left.declarations[0].id, id)]);
+    } else {
+      throw file.buildCodeFrameError(left, messages.get("unknownForHead", left.type));
+    }
+
+    var iteratorKey = scope.generateUidIdentifier("iterator");
+    var isArrayKey = scope.generateUidIdentifier("isArray");
+
+    var loop = buildForOfLoose({
+      LOOP_OBJECT: iteratorKey,
+      IS_ARRAY: isArrayKey,
+      OBJECT: node.right,
+      INDEX: scope.generateUidIdentifier("i"),
+      ID: id
+    });
+
+    if (!declar) {
+      loop.body.body.shift();
+    }
+
+    var isLabeledParent = t.isLabeledStatement(parent);
+    var labeled = void 0;
+
+    if (isLabeledParent) {
+      labeled = t.labeledStatement(parent.label, loop);
+    }
+
+    return {
+      replaceParent: isLabeledParent,
+      declar: declar,
+      node: labeled || loop,
+      loop: loop
+    };
+  }
+
+  function spec(path, file) {
+    var node = path.node,
+        scope = path.scope,
+        parent = path.parent;
+
+    var left = node.left;
+    var declar = void 0;
+
+    var stepKey = scope.generateUidIdentifier("step");
+    var stepValue = t.memberExpression(stepKey, t.identifier("value"));
+
+    if (t.isIdentifier(left) || t.isPattern(left) || t.isMemberExpression(left)) {
+      declar = t.expressionStatement(t.assignmentExpression("=", left, stepValue));
+    } else if (t.isVariableDeclaration(left)) {
+      declar = t.variableDeclaration(left.kind, [t.variableDeclarator(left.declarations[0].id, stepValue)]);
+    } else {
+      throw file.buildCodeFrameError(left, messages.get("unknownForHead", left.type));
+    }
+
+    var iteratorKey = scope.generateUidIdentifier("iterator");
+
+    var template = buildForOf({
+      ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"),
+      ITERATOR_COMPLETION: scope.generateUidIdentifier("iteratorNormalCompletion"),
+      ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"),
+      ITERATOR_KEY: iteratorKey,
+      STEP_KEY: stepKey,
+      OBJECT: node.right,
+      BODY: null
+    });
+
+    var isLabeledParent = t.isLabeledStatement(parent);
+
+    var tryBody = template[3].block.body;
+    var loop = tryBody[0];
+
+    if (isLabeledParent) {
+      tryBody[0] = t.labeledStatement(parent.label, loop);
+    }
+
+    return {
+      replaceParent: isLabeledParent,
+      declar: declar,
+      loop: loop,
+      node: template
+    };
+  }
+};
+
+module.exports = exports["default"];
+},{}],75:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function () {
+  return {
+    visitor: {
+      FunctionExpression: {
+        exit: function exit(path) {
+          if (path.key !== "value" && !path.parentPath.isObjectProperty()) {
+            var replacement = (0, _babelHelperFunctionName2.default)(path);
+            if (replacement) path.replaceWith(replacement);
+          }
+        }
+      },
+
+      ObjectProperty: function ObjectProperty(path) {
+        var value = path.get("value");
+        if (value.isFunction()) {
+          var newNode = (0, _babelHelperFunctionName2.default)(value);
+          if (newNode) value.replaceWith(newNode);
+        }
+      }
+    }
+  };
+};
+
+var _babelHelperFunctionName = require("babel-helper-function-name");
+
+var _babelHelperFunctionName2 = _interopRequireDefault(_babelHelperFunctionName);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-helper-function-name":53}],76:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function () {
+  return {
+    visitor: {
+      NumericLiteral: function NumericLiteral(_ref) {
+        var node = _ref.node;
+
+        if (node.extra && /^0[ob]/i.test(node.extra.raw)) {
+          node.extra = undefined;
+        }
+      },
+      StringLiteral: function StringLiteral(_ref2) {
+        var node = _ref2.node;
+
+        if (node.extra && /\\[u]/gi.test(node.extra.raw)) {
+          node.extra = undefined;
+        }
+      }
+    }
+  };
+};
+
+module.exports = exports["default"];
+},{}],77:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _create = require("babel-runtime/core-js/object/create");
+
+var _create2 = _interopRequireDefault(_create);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  function isValidRequireCall(path) {
+    if (!path.isCallExpression()) return false;
+    if (!path.get("callee").isIdentifier({ name: "require" })) return false;
+    if (path.scope.getBinding("require")) return false;
+
+    var args = path.get("arguments");
+    if (args.length !== 1) return false;
+
+    var arg = args[0];
+    if (!arg.isStringLiteral()) return false;
+
+    return true;
+  }
+
+  var amdVisitor = {
+    ReferencedIdentifier: function ReferencedIdentifier(_ref2) {
+      var node = _ref2.node,
+          scope = _ref2.scope;
+
+      if (node.name === "exports" && !scope.getBinding("exports")) {
+        this.hasExports = true;
+      }
+
+      if (node.name === "module" && !scope.getBinding("module")) {
+        this.hasModule = true;
+      }
+    },
+    CallExpression: function CallExpression(path) {
+      if (!isValidRequireCall(path)) return;
+      this.bareSources.push(path.node.arguments[0]);
+      path.remove();
+    },
+    VariableDeclarator: function VariableDeclarator(path) {
+      var id = path.get("id");
+      if (!id.isIdentifier()) return;
+
+      var init = path.get("init");
+      if (!isValidRequireCall(init)) return;
+
+      var source = init.node.arguments[0];
+      this.sourceNames[source.value] = true;
+      this.sources.push([id.node, source]);
+
+      path.remove();
+    }
+  };
+
+  return {
+    inherits: require("babel-plugin-transform-es2015-modules-commonjs"),
+
+    pre: function pre() {
+      this.sources = [];
+      this.sourceNames = (0, _create2.default)(null);
+
+      this.bareSources = [];
+
+      this.hasExports = false;
+      this.hasModule = false;
+    },
+
+
+    visitor: {
+      Program: {
+        exit: function exit(path) {
+          var _this = this;
+
+          if (this.ran) return;
+          this.ran = true;
+
+          path.traverse(amdVisitor, this);
+
+          var params = this.sources.map(function (source) {
+            return source[0];
+          });
+          var sources = this.sources.map(function (source) {
+            return source[1];
+          });
+
+          sources = sources.concat(this.bareSources.filter(function (str) {
+            return !_this.sourceNames[str.value];
+          }));
+
+          var moduleName = this.getModuleName();
+          if (moduleName) moduleName = t.stringLiteral(moduleName);
+
+          if (this.hasExports) {
+            sources.unshift(t.stringLiteral("exports"));
+            params.unshift(t.identifier("exports"));
+          }
+
+          if (this.hasModule) {
+            sources.unshift(t.stringLiteral("module"));
+            params.unshift(t.identifier("module"));
+          }
+
+          var node = path.node;
+
+          var factory = buildFactory({
+            PARAMS: params,
+            BODY: node.body
+          });
+          factory.expression.body.directives = node.directives;
+          node.directives = [];
+
+          node.body = [buildDefine({
+            MODULE_NAME: moduleName,
+            SOURCES: sources,
+            FACTORY: factory
+          })];
+        }
+      }
+    }
+  };
+};
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildDefine = (0, _babelTemplate2.default)("\n  define(MODULE_NAME, [SOURCES], FACTORY);\n");
+
+var buildFactory = (0, _babelTemplate2.default)("\n  (function (PARAMS) {\n    BODY;\n  })\n");
+
+module.exports = exports["default"];
+},{"babel-plugin-transform-es2015-modules-commonjs":78,"babel-runtime/core-js/object/create":100,"babel-template":114}],78:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _keys = require("babel-runtime/core-js/object/keys");
+
+var _keys2 = _interopRequireDefault(_keys);
+
+var _create = require("babel-runtime/core-js/object/create");
+
+var _create2 = _interopRequireDefault(_create);
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+exports.default = function () {
+  var REASSIGN_REMAP_SKIP = (0, _symbol2.default)();
+
+  var reassignmentVisitor = {
+    ReferencedIdentifier: function ReferencedIdentifier(path) {
+      var name = path.node.name;
+      var remap = this.remaps[name];
+      if (!remap) return;
+
+      if (this.scope.getBinding(name) !== path.scope.getBinding(name)) return;
+
+      if (path.parentPath.isCallExpression({ callee: path.node })) {
+        path.replaceWith(t.sequenceExpression([t.numericLiteral(0), remap]));
+      } else if (path.isJSXIdentifier() && t.isMemberExpression(remap)) {
+        var object = remap.object,
+            property = remap.property;
+
+        path.replaceWith(t.JSXMemberExpression(t.JSXIdentifier(object.name), t.JSXIdentifier(property.name)));
+      } else {
+        path.replaceWith(remap);
+      }
+      this.requeueInParent(path);
+    },
+    AssignmentExpression: function AssignmentExpression(path) {
+      var node = path.node;
+      if (node[REASSIGN_REMAP_SKIP]) return;
+
+      var left = path.get("left");
+      if (left.isIdentifier()) {
+        var name = left.node.name;
+        var exports = this.exports[name];
+        if (!exports) return;
+
+        if (this.scope.getBinding(name) !== path.scope.getBinding(name)) return;
+
+        node[REASSIGN_REMAP_SKIP] = true;
+
+        for (var _iterator = exports, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+          var _ref;
+
+          if (_isArray) {
+            if (_i >= _iterator.length) break;
+            _ref = _iterator[_i++];
+          } else {
+            _i = _iterator.next();
+            if (_i.done) break;
+            _ref = _i.value;
+          }
+
+          var reid = _ref;
+
+          node = buildExportsAssignment(reid, node).expression;
+        }
+
+        path.replaceWith(node);
+        this.requeueInParent(path);
+      } else if (left.isObjectPattern()) {
+        for (var _iterator2 = left.node.properties, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+          var _ref2;
+
+          if (_isArray2) {
+            if (_i2 >= _iterator2.length) break;
+            _ref2 = _iterator2[_i2++];
+          } else {
+            _i2 = _iterator2.next();
+            if (_i2.done) break;
+            _ref2 = _i2.value;
+          }
+
+          var property = _ref2;
+
+          var _name = property.value.name;
+
+          var _exports = this.exports[_name];
+          if (!_exports) continue;
+
+          if (this.scope.getBinding(_name) !== path.scope.getBinding(_name)) return;
+
+          node[REASSIGN_REMAP_SKIP] = true;
+
+          path.insertAfter(buildExportsAssignment(t.identifier(_name), t.identifier(_name)));
+        }
+      } else if (left.isArrayPattern()) {
+        for (var _iterator3 = left.node.elements, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+          var _ref3;
+
+          if (_isArray3) {
+            if (_i3 >= _iterator3.length) break;
+            _ref3 = _iterator3[_i3++];
+          } else {
+            _i3 = _iterator3.next();
+            if (_i3.done) break;
+            _ref3 = _i3.value;
+          }
+
+          var element = _ref3;
+
+          if (!element) continue;
+          var _name2 = element.name;
+
+          var _exports2 = this.exports[_name2];
+          if (!_exports2) continue;
+
+          if (this.scope.getBinding(_name2) !== path.scope.getBinding(_name2)) return;
+
+          node[REASSIGN_REMAP_SKIP] = true;
+
+          path.insertAfter(buildExportsAssignment(t.identifier(_name2), t.identifier(_name2)));
+        }
+      }
+    },
+    UpdateExpression: function UpdateExpression(path) {
+      var arg = path.get("argument");
+      if (!arg.isIdentifier()) return;
+
+      var name = arg.node.name;
+      var exports = this.exports[name];
+      if (!exports) return;
+
+      if (this.scope.getBinding(name) !== path.scope.getBinding(name)) return;
+
+      var node = t.assignmentExpression(path.node.operator[0] + "=", arg.node, t.numericLiteral(1));
+
+      if (path.parentPath.isExpressionStatement() && !path.isCompletionRecord() || path.node.prefix) {
+        path.replaceWith(node);
+        this.requeueInParent(path);
+        return;
+      }
+
+      var nodes = [];
+      nodes.push(node);
+
+      var operator = void 0;
+      if (path.node.operator === "--") {
+        operator = "+";
+      } else {
+        operator = "-";
+      }
+      nodes.push(t.binaryExpression(operator, arg.node, t.numericLiteral(1)));
+
+      path.replaceWithMultiple(t.sequenceExpression(nodes));
+    }
+  };
+
+  return {
+    inherits: _babelPluginTransformStrictMode2.default,
+
+    visitor: {
+      ThisExpression: function ThisExpression(path, state) {
+        if (this.ranCommonJS) return;
+
+        if (state.opts.allowTopLevelThis !== true && !path.findParent(function (path) {
+          return !path.is("shadow") && THIS_BREAK_KEYS.indexOf(path.type) >= 0;
+        })) {
+          path.replaceWith(t.identifier("undefined"));
+        }
+      },
+
+
+      Program: {
+        exit: function exit(path) {
+          this.ranCommonJS = true;
+
+          var strict = !!this.opts.strict;
+          var noInterop = !!this.opts.noInterop;
+
+          var scope = path.scope;
+
+          scope.rename("module");
+          scope.rename("exports");
+          scope.rename("require");
+
+          var hasExports = false;
+          var hasImports = false;
+
+          var body = path.get("body");
+          var imports = (0, _create2.default)(null);
+          var exports = (0, _create2.default)(null);
+
+          var nonHoistedExportNames = (0, _create2.default)(null);
+
+          var topNodes = [];
+          var remaps = (0, _create2.default)(null);
+
+          var requires = (0, _create2.default)(null);
+
+          function addRequire(source, blockHoist) {
+            var cached = requires[source];
+            if (cached) return cached;
+
+            var ref = path.scope.generateUidIdentifier((0, _path2.basename)(source, (0, _path2.extname)(source)));
+
+            var varDecl = t.variableDeclaration("var", [t.variableDeclarator(ref, buildRequire(t.stringLiteral(source)).expression)]);
+
+            if (imports[source]) {
+              varDecl.loc = imports[source].loc;
+            }
+
+            if (typeof blockHoist === "number" && blockHoist > 0) {
+              varDecl._blockHoist = blockHoist;
+            }
+
+            topNodes.push(varDecl);
+
+            return requires[source] = ref;
+          }
+
+          function addTo(obj, key, arr) {
+            var existing = obj[key] || [];
+            obj[key] = existing.concat(arr);
+          }
+
+          for (var _iterator4 = body, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : (0, _getIterator3.default)(_iterator4);;) {
+            var _ref4;
+
+            if (_isArray4) {
+              if (_i4 >= _iterator4.length) break;
+              _ref4 = _iterator4[_i4++];
+            } else {
+              _i4 = _iterator4.next();
+              if (_i4.done) break;
+              _ref4 = _i4.value;
+            }
+
+            var _path = _ref4;
+
+            if (_path.isExportDeclaration()) {
+              hasExports = true;
+
+              var specifiers = [].concat(_path.get("declaration"), _path.get("specifiers"));
+              for (var _iterator6 = specifiers, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : (0, _getIterator3.default)(_iterator6);;) {
+                var _ref6;
+
+                if (_isArray6) {
+                  if (_i6 >= _iterator6.length) break;
+                  _ref6 = _iterator6[_i6++];
+                } else {
+                  _i6 = _iterator6.next();
+                  if (_i6.done) break;
+                  _ref6 = _i6.value;
+                }
+
+                var _specifier2 = _ref6;
+
+                var ids = _specifier2.getBindingIdentifiers();
+                if (ids.__esModule) {
+                  throw _specifier2.buildCodeFrameError("Illegal export \"__esModule\"");
+                }
+              }
+            }
+
+            if (_path.isImportDeclaration()) {
+              var _importsEntry$specifi;
+
+              hasImports = true;
+
+              var key = _path.node.source.value;
+              var importsEntry = imports[key] || {
+                specifiers: [],
+                maxBlockHoist: 0,
+                loc: _path.node.loc
+              };
+
+              (_importsEntry$specifi = importsEntry.specifiers).push.apply(_importsEntry$specifi, _path.node.specifiers);
+
+              if (typeof _path.node._blockHoist === "number") {
+                importsEntry.maxBlockHoist = Math.max(_path.node._blockHoist, importsEntry.maxBlockHoist);
+              }
+
+              imports[key] = importsEntry;
+
+              _path.remove();
+            } else if (_path.isExportDefaultDeclaration()) {
+              var declaration = _path.get("declaration");
+              if (declaration.isFunctionDeclaration()) {
+                var id = declaration.node.id;
+                var defNode = t.identifier("default");
+                if (id) {
+                  addTo(exports, id.name, defNode);
+                  topNodes.push(buildExportsAssignment(defNode, id));
+                  _path.replaceWith(declaration.node);
+                } else {
+                  topNodes.push(buildExportsAssignment(defNode, t.toExpression(declaration.node)));
+                  _path.remove();
+                }
+              } else if (declaration.isClassDeclaration()) {
+                var _id = declaration.node.id;
+                var _defNode = t.identifier("default");
+                if (_id) {
+                  addTo(exports, _id.name, _defNode);
+                  _path.replaceWithMultiple([declaration.node, buildExportsAssignment(_defNode, _id)]);
+                } else {
+                  _path.replaceWith(buildExportsAssignment(_defNode, t.toExpression(declaration.node)));
+
+                  _path.parentPath.requeue(_path.get("expression.left"));
+                }
+              } else {
+                _path.replaceWith(buildExportsAssignment(t.identifier("default"), declaration.node));
+
+                _path.parentPath.requeue(_path.get("expression.left"));
+              }
+            } else if (_path.isExportNamedDeclaration()) {
+              var _declaration = _path.get("declaration");
+              if (_declaration.node) {
+                if (_declaration.isFunctionDeclaration()) {
+                  var _id2 = _declaration.node.id;
+                  addTo(exports, _id2.name, _id2);
+                  topNodes.push(buildExportsAssignment(_id2, _id2));
+                  _path.replaceWith(_declaration.node);
+                } else if (_declaration.isClassDeclaration()) {
+                  var _id3 = _declaration.node.id;
+                  addTo(exports, _id3.name, _id3);
+                  _path.replaceWithMultiple([_declaration.node, buildExportsAssignment(_id3, _id3)]);
+                  nonHoistedExportNames[_id3.name] = true;
+                } else if (_declaration.isVariableDeclaration()) {
+                  var declarators = _declaration.get("declarations");
+                  for (var _iterator7 = declarators, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : (0, _getIterator3.default)(_iterator7);;) {
+                    var _ref7;
+
+                    if (_isArray7) {
+                      if (_i7 >= _iterator7.length) break;
+                      _ref7 = _iterator7[_i7++];
+                    } else {
+                      _i7 = _iterator7.next();
+                      if (_i7.done) break;
+                      _ref7 = _i7.value;
+                    }
+
+                    var decl = _ref7;
+
+                    var _id4 = decl.get("id");
+
+                    var init = decl.get("init");
+                    var exportsToInsert = [];
+                    if (!init.node) init.replaceWith(t.identifier("undefined"));
+
+                    if (_id4.isIdentifier()) {
+                      addTo(exports, _id4.node.name, _id4.node);
+                      init.replaceWith(buildExportsAssignment(_id4.node, init.node).expression);
+                      nonHoistedExportNames[_id4.node.name] = true;
+                    } else if (_id4.isObjectPattern()) {
+                      for (var _i8 = 0; _i8 < _id4.node.properties.length; _i8++) {
+                        var prop = _id4.node.properties[_i8];
+                        var propValue = prop.value;
+                        if (t.isAssignmentPattern(propValue)) {
+                          propValue = propValue.left;
+                        } else if (t.isRestProperty(prop)) {
+                          propValue = prop.argument;
+                        }
+                        addTo(exports, propValue.name, propValue);
+                        exportsToInsert.push(buildExportsAssignment(propValue, propValue));
+                        nonHoistedExportNames[propValue.name] = true;
+                      }
+                    } else if (_id4.isArrayPattern() && _id4.node.elements) {
+                      for (var _i9 = 0; _i9 < _id4.node.elements.length; _i9++) {
+                        var elem = _id4.node.elements[_i9];
+                        if (!elem) continue;
+                        if (t.isAssignmentPattern(elem)) {
+                          elem = elem.left;
+                        } else if (t.isRestElement(elem)) {
+                          elem = elem.argument;
+                        }
+                        var name = elem.name;
+                        addTo(exports, name, elem);
+                        exportsToInsert.push(buildExportsAssignment(elem, elem));
+                        nonHoistedExportNames[name] = true;
+                      }
+                    }
+                    _path.insertAfter(exportsToInsert);
+                  }
+                  _path.replaceWith(_declaration.node);
+                }
+                continue;
+              }
+
+              var _specifiers = _path.get("specifiers");
+              var nodes = [];
+              var _source = _path.node.source;
+              if (_source) {
+                var ref = addRequire(_source.value, _path.node._blockHoist);
+
+                for (var _iterator8 = _specifiers, _isArray8 = Array.isArray(_iterator8), _i10 = 0, _iterator8 = _isArray8 ? _iterator8 : (0, _getIterator3.default)(_iterator8);;) {
+                  var _ref8;
+
+                  if (_isArray8) {
+                    if (_i10 >= _iterator8.length) break;
+                    _ref8 = _iterator8[_i10++];
+                  } else {
+                    _i10 = _iterator8.next();
+                    if (_i10.done) break;
+                    _ref8 = _i10.value;
+                  }
+
+                  var _specifier3 = _ref8;
+
+                  if (_specifier3.isExportNamespaceSpecifier()) {} else if (_specifier3.isExportDefaultSpecifier()) {} else if (_specifier3.isExportSpecifier()) {
+                    if (!noInterop && _specifier3.node.local.name === "default") {
+                      topNodes.push(buildExportsFrom(t.stringLiteral(_specifier3.node.exported.name), t.memberExpression(t.callExpression(this.addHelper("interopRequireDefault"), [ref]), _specifier3.node.local)));
+                    } else {
+                      topNodes.push(buildExportsFrom(t.stringLiteral(_specifier3.node.exported.name), t.memberExpression(ref, _specifier3.node.local)));
+                    }
+                    nonHoistedExportNames[_specifier3.node.exported.name] = true;
+                  }
+                }
+              } else {
+                for (var _iterator9 = _specifiers, _isArray9 = Array.isArray(_iterator9), _i11 = 0, _iterator9 = _isArray9 ? _iterator9 : (0, _getIterator3.default)(_iterator9);;) {
+                  var _ref9;
+
+                  if (_isArray9) {
+                    if (_i11 >= _iterator9.length) break;
+                    _ref9 = _iterator9[_i11++];
+                  } else {
+                    _i11 = _iterator9.next();
+                    if (_i11.done) break;
+                    _ref9 = _i11.value;
+                  }
+
+                  var _specifier4 = _ref9;
+
+                  if (_specifier4.isExportSpecifier()) {
+                    addTo(exports, _specifier4.node.local.name, _specifier4.node.exported);
+                    nonHoistedExportNames[_specifier4.node.exported.name] = true;
+                    nodes.push(buildExportsAssignment(_specifier4.node.exported, _specifier4.node.local));
+                  }
+                }
+              }
+              _path.replaceWithMultiple(nodes);
+            } else if (_path.isExportAllDeclaration()) {
+              var exportNode = buildExportAll({
+                OBJECT: addRequire(_path.node.source.value, _path.node._blockHoist)
+              });
+              exportNode.loc = _path.node.loc;
+              topNodes.push(exportNode);
+              _path.remove();
+            }
+          }
+
+          for (var source in imports) {
+            var _imports$source = imports[source],
+                specifiers = _imports$source.specifiers,
+                maxBlockHoist = _imports$source.maxBlockHoist;
+
+            if (specifiers.length) {
+              var uid = addRequire(source, maxBlockHoist);
+
+              var wildcard = void 0;
+
+              for (var i = 0; i < specifiers.length; i++) {
+                var specifier = specifiers[i];
+                if (t.isImportNamespaceSpecifier(specifier)) {
+                  if (strict || noInterop) {
+                    remaps[specifier.local.name] = uid;
+                  } else {
+                    var varDecl = t.variableDeclaration("var", [t.variableDeclarator(specifier.local, t.callExpression(this.addHelper("interopRequireWildcard"), [uid]))]);
+
+                    if (maxBlockHoist > 0) {
+                      varDecl._blockHoist = maxBlockHoist;
+                    }
+
+                    topNodes.push(varDecl);
+                  }
+                  wildcard = specifier.local;
+                } else if (t.isImportDefaultSpecifier(specifier)) {
+                  specifiers[i] = t.importSpecifier(specifier.local, t.identifier("default"));
+                }
+              }
+
+              for (var _iterator5 = specifiers, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : (0, _getIterator3.default)(_iterator5);;) {
+                var _ref5;
+
+                if (_isArray5) {
+                  if (_i5 >= _iterator5.length) break;
+                  _ref5 = _iterator5[_i5++];
+                } else {
+                  _i5 = _iterator5.next();
+                  if (_i5.done) break;
+                  _ref5 = _i5.value;
+                }
+
+                var _specifier = _ref5;
+
+                if (t.isImportSpecifier(_specifier)) {
+                  var target = uid;
+                  if (_specifier.imported.name === "default") {
+                    if (wildcard) {
+                      target = wildcard;
+                    } else if (!noInterop) {
+                      target = wildcard = path.scope.generateUidIdentifier(uid.name);
+                      var _varDecl = t.variableDeclaration("var", [t.variableDeclarator(target, t.callExpression(this.addHelper("interopRequireDefault"), [uid]))]);
+
+                      if (maxBlockHoist > 0) {
+                        _varDecl._blockHoist = maxBlockHoist;
+                      }
+
+                      topNodes.push(_varDecl);
+                    }
+                  }
+                  remaps[_specifier.local.name] = t.memberExpression(target, t.cloneWithoutLoc(_specifier.imported));
+                }
+              }
+            } else {
+              var requireNode = buildRequire(t.stringLiteral(source));
+              requireNode.loc = imports[source].loc;
+              topNodes.push(requireNode);
+            }
+          }
+
+          if (hasImports && (0, _keys2.default)(nonHoistedExportNames).length) {
+            var maxHoistedExportsNodeAssignmentLength = 100;
+            var nonHoistedExportNamesArr = (0, _keys2.default)(nonHoistedExportNames);
+
+            var _loop = function _loop(currentExportsNodeAssignmentLength) {
+              var nonHoistedExportNamesChunk = nonHoistedExportNamesArr.slice(currentExportsNodeAssignmentLength, currentExportsNodeAssignmentLength + maxHoistedExportsNodeAssignmentLength);
+
+              var hoistedExportsNode = t.identifier("undefined");
+
+              nonHoistedExportNamesChunk.forEach(function (name) {
+                hoistedExportsNode = buildExportsAssignment(t.identifier(name), hoistedExportsNode).expression;
+              });
+
+              var node = t.expressionStatement(hoistedExportsNode);
+              node._blockHoist = 3;
+
+              topNodes.unshift(node);
+            };
+
+            for (var currentExportsNodeAssignmentLength = 0; currentExportsNodeAssignmentLength < nonHoistedExportNamesArr.length; currentExportsNodeAssignmentLength += maxHoistedExportsNodeAssignmentLength) {
+              _loop(currentExportsNodeAssignmentLength);
+            }
+          }
+
+          if (hasExports && !strict) {
+            var buildTemplate = buildExportsModuleDeclaration;
+            if (this.opts.loose) buildTemplate = buildLooseExportsModuleDeclaration;
+
+            var declar = buildTemplate();
+            declar._blockHoist = 3;
+
+            topNodes.unshift(declar);
+          }
+
+          path.unshiftContainer("body", topNodes);
+          path.traverse(reassignmentVisitor, {
+            remaps: remaps,
+            scope: scope,
+            exports: exports,
+            requeueInParent: function requeueInParent(newPath) {
+              return path.requeue(newPath);
+            }
+          });
+        }
+      }
+    }
+  };
+};
+
+var _path2 = require("path");
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+var _babelPluginTransformStrictMode = require("babel-plugin-transform-strict-mode");
+
+var _babelPluginTransformStrictMode2 = _interopRequireDefault(_babelPluginTransformStrictMode);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildRequire = (0, _babelTemplate2.default)("\n  require($0);\n");
+
+var buildExportsModuleDeclaration = (0, _babelTemplate2.default)("\n  Object.defineProperty(exports, \"__esModule\", {\n    value: true\n  });\n");
+
+var buildExportsFrom = (0, _babelTemplate2.default)("\n  Object.defineProperty(exports, $0, {\n    enumerable: true,\n    get: function () {\n      return $1;\n    }\n  });\n");
+
+var buildLooseExportsModuleDeclaration = (0, _babelTemplate2.default)("\n  exports.__esModule = true;\n");
+
+var buildExportsAssignment = (0, _babelTemplate2.default)("\n  exports.$0 = $1;\n");
+
+var buildExportAll = (0, _babelTemplate2.default)("\n  Object.keys(OBJECT).forEach(function (key) {\n    if (key === \"default\" || key === \"__esModule\") return;\n    Object.defineProperty(exports, key, {\n      enumerable: true,\n      get: function () {\n        return OBJECT[key];\n      }\n    });\n  });\n");
+
+var THIS_BREAK_KEYS = ["FunctionExpression", "FunctionDeclaration", "ClassProperty", "ClassMethod", "ObjectMethod"];
+
+module.exports = exports["default"];
+},{"babel-plugin-transform-strict-mode":93,"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/object/create":100,"babel-runtime/core-js/object/keys":102,"babel-runtime/core-js/symbol":104,"babel-template":114,"babel-types":151,"path":522}],79:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _create = require("babel-runtime/core-js/object/create");
+
+var _create2 = _interopRequireDefault(_create);
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  var IGNORE_REASSIGNMENT_SYMBOL = (0, _symbol2.default)();
+
+  var reassignmentVisitor = {
+    "AssignmentExpression|UpdateExpression": function AssignmentExpressionUpdateExpression(path) {
+      if (path.node[IGNORE_REASSIGNMENT_SYMBOL]) return;
+      path.node[IGNORE_REASSIGNMENT_SYMBOL] = true;
+
+      var arg = path.get(path.isAssignmentExpression() ? "left" : "argument");
+      if (!arg.isIdentifier()) return;
+
+      var name = arg.node.name;
+
+      if (this.scope.getBinding(name) !== path.scope.getBinding(name)) return;
+
+      var exportedNames = this.exports[name];
+      if (!exportedNames) return;
+
+      var node = path.node;
+
+      var isPostUpdateExpression = path.isUpdateExpression() && !node.prefix;
+      if (isPostUpdateExpression) {
+        if (node.operator === "++") node = t.binaryExpression("+", node.argument, t.numericLiteral(1));else if (node.operator === "--") node = t.binaryExpression("-", node.argument, t.numericLiteral(1));else isPostUpdateExpression = false;
+      }
+
+      for (var _iterator = exportedNames, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+        var _ref2;
+
+        if (_isArray) {
+          if (_i >= _iterator.length) break;
+          _ref2 = _iterator[_i++];
+        } else {
+          _i = _iterator.next();
+          if (_i.done) break;
+          _ref2 = _i.value;
+        }
+
+        var exportedName = _ref2;
+
+        node = this.buildCall(exportedName, node).expression;
+      }
+
+      if (isPostUpdateExpression) node = t.sequenceExpression([node, path.node]);
+
+      path.replaceWith(node);
+    }
+  };
+
+  return {
+    visitor: {
+      CallExpression: function CallExpression(path, state) {
+        if (path.node.callee.type === TYPE_IMPORT) {
+          var contextIdent = state.contextIdent;
+          path.replaceWith(t.callExpression(t.memberExpression(contextIdent, t.identifier("import")), path.node.arguments));
+        }
+      },
+      ReferencedIdentifier: function ReferencedIdentifier(path, state) {
+        if (path.node.name == "__moduleName" && !path.scope.hasBinding("__moduleName")) {
+          path.replaceWith(t.memberExpression(state.contextIdent, t.identifier("id")));
+        }
+      },
+
+
+      Program: {
+        enter: function enter(path, state) {
+          state.contextIdent = path.scope.generateUidIdentifier("context");
+        },
+        exit: function exit(path, state) {
+          var exportIdent = path.scope.generateUidIdentifier("export");
+          var contextIdent = state.contextIdent;
+
+          var exportNames = (0, _create2.default)(null);
+          var modules = [];
+
+          var beforeBody = [];
+          var setters = [];
+          var sources = [];
+          var variableIds = [];
+          var removedPaths = [];
+
+          function addExportName(key, val) {
+            exportNames[key] = exportNames[key] || [];
+            exportNames[key].push(val);
+          }
+
+          function pushModule(source, key, specifiers) {
+            var module = void 0;
+            modules.forEach(function (m) {
+              if (m.key === source) {
+                module = m;
+              }
+            });
+            if (!module) {
+              modules.push(module = { key: source, imports: [], exports: [] });
+            }
+            module[key] = module[key].concat(specifiers);
+          }
+
+          function buildExportCall(name, val) {
+            return t.expressionStatement(t.callExpression(exportIdent, [t.stringLiteral(name), val]));
+          }
+
+          var body = path.get("body");
+
+          var canHoist = true;
+          for (var _iterator2 = body, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+            var _ref3;
+
+            if (_isArray2) {
+              if (_i2 >= _iterator2.length) break;
+              _ref3 = _iterator2[_i2++];
+            } else {
+              _i2 = _iterator2.next();
+              if (_i2.done) break;
+              _ref3 = _i2.value;
+            }
+
+            var _path = _ref3;
+
+            if (_path.isExportDeclaration()) _path = _path.get("declaration");
+            if (_path.isVariableDeclaration() && _path.node.kind !== "var") {
+              canHoist = false;
+              break;
+            }
+          }
+
+          for (var _iterator3 = body, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+            var _ref4;
+
+            if (_isArray3) {
+              if (_i3 >= _iterator3.length) break;
+              _ref4 = _iterator3[_i3++];
+            } else {
+              _i3 = _iterator3.next();
+              if (_i3.done) break;
+              _ref4 = _i3.value;
+            }
+
+            var _path2 = _ref4;
+
+            if (canHoist && _path2.isFunctionDeclaration()) {
+              beforeBody.push(_path2.node);
+              removedPaths.push(_path2);
+            } else if (_path2.isImportDeclaration()) {
+              var source = _path2.node.source.value;
+              pushModule(source, "imports", _path2.node.specifiers);
+              for (var name in _path2.getBindingIdentifiers()) {
+                _path2.scope.removeBinding(name);
+                variableIds.push(t.identifier(name));
+              }
+              _path2.remove();
+            } else if (_path2.isExportAllDeclaration()) {
+              pushModule(_path2.node.source.value, "exports", _path2.node);
+              _path2.remove();
+            } else if (_path2.isExportDefaultDeclaration()) {
+              var declar = _path2.get("declaration");
+              if (declar.isClassDeclaration() || declar.isFunctionDeclaration()) {
+                var id = declar.node.id;
+                var nodes = [];
+
+                if (id) {
+                  nodes.push(declar.node);
+                  nodes.push(buildExportCall("default", id));
+                  addExportName(id.name, "default");
+                } else {
+                  nodes.push(buildExportCall("default", t.toExpression(declar.node)));
+                }
+
+                if (!canHoist || declar.isClassDeclaration()) {
+                  _path2.replaceWithMultiple(nodes);
+                } else {
+                  beforeBody = beforeBody.concat(nodes);
+                  removedPaths.push(_path2);
+                }
+              } else {
+                _path2.replaceWith(buildExportCall("default", declar.node));
+              }
+            } else if (_path2.isExportNamedDeclaration()) {
+              var _declar = _path2.get("declaration");
+
+              if (_declar.node) {
+                _path2.replaceWith(_declar);
+
+                var _nodes = [];
+                var bindingIdentifiers = void 0;
+                if (_path2.isFunction()) {
+                  var node = _declar.node;
+                  var _name = node.id.name;
+                  if (canHoist) {
+                    addExportName(_name, _name);
+                    beforeBody.push(node);
+                    beforeBody.push(buildExportCall(_name, node.id));
+                    removedPaths.push(_path2);
+                  } else {
+                    var _bindingIdentifiers;
+
+                    bindingIdentifiers = (_bindingIdentifiers = {}, _bindingIdentifiers[_name] = node.id, _bindingIdentifiers);
+                  }
+                } else {
+                  bindingIdentifiers = _declar.getBindingIdentifiers();
+                }
+                for (var _name2 in bindingIdentifiers) {
+                  addExportName(_name2, _name2);
+                  _nodes.push(buildExportCall(_name2, t.identifier(_name2)));
+                }
+                _path2.insertAfter(_nodes);
+              } else {
+                var specifiers = _path2.node.specifiers;
+                if (specifiers && specifiers.length) {
+                  if (_path2.node.source) {
+                    pushModule(_path2.node.source.value, "exports", specifiers);
+                    _path2.remove();
+                  } else {
+                    var _nodes2 = [];
+
+                    for (var _iterator7 = specifiers, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : (0, _getIterator3.default)(_iterator7);;) {
+                      var _ref8;
+
+                      if (_isArray7) {
+                        if (_i7 >= _iterator7.length) break;
+                        _ref8 = _iterator7[_i7++];
+                      } else {
+                        _i7 = _iterator7.next();
+                        if (_i7.done) break;
+                        _ref8 = _i7.value;
+                      }
+
+                      var specifier = _ref8;
+
+                      _nodes2.push(buildExportCall(specifier.exported.name, specifier.local));
+                      addExportName(specifier.local.name, specifier.exported.name);
+                    }
+
+                    _path2.replaceWithMultiple(_nodes2);
+                  }
+                }
+              }
+            }
+          }
+
+          modules.forEach(function (specifiers) {
+            var setterBody = [];
+            var target = path.scope.generateUidIdentifier(specifiers.key);
+
+            for (var _iterator4 = specifiers.imports, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : (0, _getIterator3.default)(_iterator4);;) {
+              var _ref5;
+
+              if (_isArray4) {
+                if (_i4 >= _iterator4.length) break;
+                _ref5 = _iterator4[_i4++];
+              } else {
+                _i4 = _iterator4.next();
+                if (_i4.done) break;
+                _ref5 = _i4.value;
+              }
+
+              var specifier = _ref5;
+
+              if (t.isImportNamespaceSpecifier(specifier)) {
+                setterBody.push(t.expressionStatement(t.assignmentExpression("=", specifier.local, target)));
+              } else if (t.isImportDefaultSpecifier(specifier)) {
+                specifier = t.importSpecifier(specifier.local, t.identifier("default"));
+              }
+
+              if (t.isImportSpecifier(specifier)) {
+                setterBody.push(t.expressionStatement(t.assignmentExpression("=", specifier.local, t.memberExpression(target, specifier.imported))));
+              }
+            }
+
+            if (specifiers.exports.length) {
+              var exportObjRef = path.scope.generateUidIdentifier("exportObj");
+
+              setterBody.push(t.variableDeclaration("var", [t.variableDeclarator(exportObjRef, t.objectExpression([]))]));
+
+              for (var _iterator5 = specifiers.exports, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : (0, _getIterator3.default)(_iterator5);;) {
+                var _ref6;
+
+                if (_isArray5) {
+                  if (_i5 >= _iterator5.length) break;
+                  _ref6 = _iterator5[_i5++];
+                } else {
+                  _i5 = _iterator5.next();
+                  if (_i5.done) break;
+                  _ref6 = _i5.value;
+                }
+
+                var node = _ref6;
+
+                if (t.isExportAllDeclaration(node)) {
+                  setterBody.push(buildExportAll({
+                    KEY: path.scope.generateUidIdentifier("key"),
+                    EXPORT_OBJ: exportObjRef,
+                    TARGET: target
+                  }));
+                } else if (t.isExportSpecifier(node)) {
+                  setterBody.push(t.expressionStatement(t.assignmentExpression("=", t.memberExpression(exportObjRef, node.exported), t.memberExpression(target, node.local))));
+                } else {}
+              }
+
+              setterBody.push(t.expressionStatement(t.callExpression(exportIdent, [exportObjRef])));
+            }
+
+            sources.push(t.stringLiteral(specifiers.key));
+            setters.push(t.functionExpression(null, [target], t.blockStatement(setterBody)));
+          });
+
+          var moduleName = this.getModuleName();
+          if (moduleName) moduleName = t.stringLiteral(moduleName);
+
+          if (canHoist) {
+            (0, _babelHelperHoistVariables2.default)(path, function (id) {
+              return variableIds.push(id);
+            });
+          }
+
+          if (variableIds.length) {
+            beforeBody.unshift(t.variableDeclaration("var", variableIds.map(function (id) {
+              return t.variableDeclarator(id);
+            })));
+          }
+
+          path.traverse(reassignmentVisitor, {
+            exports: exportNames,
+            buildCall: buildExportCall,
+            scope: path.scope
+          });
+
+          for (var _iterator6 = removedPaths, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : (0, _getIterator3.default)(_iterator6);;) {
+            var _ref7;
+
+            if (_isArray6) {
+              if (_i6 >= _iterator6.length) break;
+              _ref7 = _iterator6[_i6++];
+            } else {
+              _i6 = _iterator6.next();
+              if (_i6.done) break;
+              _ref7 = _i6.value;
+            }
+
+            var _path3 = _ref7;
+
+            _path3.remove();
+          }
+
+          path.node.body = [buildTemplate({
+            SYSTEM_REGISTER: t.memberExpression(t.identifier(state.opts.systemGlobal || "System"), t.identifier("register")),
+            BEFORE_BODY: beforeBody,
+            MODULE_NAME: moduleName,
+            SETTERS: setters,
+            SOURCES: sources,
+            BODY: path.node.body,
+            EXPORT_IDENTIFIER: exportIdent,
+            CONTEXT_IDENTIFIER: contextIdent
+          })];
+        }
+      }
+    }
+  };
+};
+
+var _babelHelperHoistVariables = require("babel-helper-hoist-variables");
+
+var _babelHelperHoistVariables2 = _interopRequireDefault(_babelHelperHoistVariables);
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildTemplate = (0, _babelTemplate2.default)("\n  SYSTEM_REGISTER(MODULE_NAME, [SOURCES], function (EXPORT_IDENTIFIER, CONTEXT_IDENTIFIER) {\n    \"use strict\";\n    BEFORE_BODY;\n    return {\n      setters: [SETTERS],\n      execute: function () {\n        BODY;\n      }\n    };\n  });\n");
+
+var buildExportAll = (0, _babelTemplate2.default)("\n  for (var KEY in TARGET) {\n    if (KEY !== \"default\" && KEY !== \"__esModule\") EXPORT_OBJ[KEY] = TARGET[KEY];\n  }\n");
+
+var TYPE_IMPORT = "Import";
+
+module.exports = exports["default"];
+},{"babel-helper-hoist-variables":55,"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/object/create":100,"babel-runtime/core-js/symbol":104,"babel-template":114}],80:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  function isValidDefine(path) {
+    if (!path.isExpressionStatement()) return;
+
+    var expr = path.get("expression");
+    if (!expr.isCallExpression()) return false;
+    if (!expr.get("callee").isIdentifier({ name: "define" })) return false;
+
+    var args = expr.get("arguments");
+    if (args.length === 3 && !args.shift().isStringLiteral()) return false;
+    if (args.length !== 2) return false;
+    if (!args.shift().isArrayExpression()) return false;
+    if (!args.shift().isFunctionExpression()) return false;
+
+    return true;
+  }
+
+  return {
+    inherits: require("babel-plugin-transform-es2015-modules-amd"),
+
+    visitor: {
+      Program: {
+        exit: function exit(path, state) {
+          var last = path.get("body").pop();
+          if (!isValidDefine(last)) return;
+
+          var call = last.node.expression;
+          var args = call.arguments;
+
+          var moduleName = args.length === 3 ? args.shift() : null;
+          var amdArgs = call.arguments[0];
+          var func = call.arguments[1];
+          var browserGlobals = state.opts.globals || {};
+
+          var commonArgs = amdArgs.elements.map(function (arg) {
+            if (arg.value === "module" || arg.value === "exports") {
+              return t.identifier(arg.value);
+            } else {
+              return t.callExpression(t.identifier("require"), [arg]);
+            }
+          });
+
+          var browserArgs = amdArgs.elements.map(function (arg) {
+            if (arg.value === "module") {
+              return t.identifier("mod");
+            } else if (arg.value === "exports") {
+              return t.memberExpression(t.identifier("mod"), t.identifier("exports"));
+            } else {
+              var memberExpression = void 0;
+
+              if (state.opts.exactGlobals) {
+                var globalRef = browserGlobals[arg.value];
+                if (globalRef) {
+                  memberExpression = globalRef.split(".").reduce(function (accum, curr) {
+                    return t.memberExpression(accum, t.identifier(curr));
+                  }, t.identifier("global"));
+                } else {
+                  memberExpression = t.memberExpression(t.identifier("global"), t.identifier(t.toIdentifier(arg.value)));
+                }
+              } else {
+                var requireName = (0, _path.basename)(arg.value, (0, _path.extname)(arg.value));
+                var globalName = browserGlobals[requireName] || requireName;
+                memberExpression = t.memberExpression(t.identifier("global"), t.identifier(t.toIdentifier(globalName)));
+              }
+
+              return memberExpression;
+            }
+          });
+
+          var moduleNameOrBasename = moduleName ? moduleName.value : this.file.opts.basename;
+          var globalToAssign = t.memberExpression(t.identifier("global"), t.identifier(t.toIdentifier(moduleNameOrBasename)));
+          var prerequisiteAssignments = null;
+
+          if (state.opts.exactGlobals) {
+            var globalName = browserGlobals[moduleNameOrBasename];
+
+            if (globalName) {
+              prerequisiteAssignments = [];
+
+              var members = globalName.split(".");
+              globalToAssign = members.slice(1).reduce(function (accum, curr) {
+                prerequisiteAssignments.push(buildPrerequisiteAssignment({ GLOBAL_REFERENCE: accum }));
+                return t.memberExpression(accum, t.identifier(curr));
+              }, t.memberExpression(t.identifier("global"), t.identifier(members[0])));
+            }
+          }
+
+          var globalExport = buildGlobalExport({
+            BROWSER_ARGUMENTS: browserArgs,
+            PREREQUISITE_ASSIGNMENTS: prerequisiteAssignments,
+            GLOBAL_TO_ASSIGN: globalToAssign
+          });
+
+          last.replaceWith(buildWrapper({
+            MODULE_NAME: moduleName,
+            AMD_ARGUMENTS: amdArgs,
+            COMMON_ARGUMENTS: commonArgs,
+            GLOBAL_EXPORT: globalExport,
+            FUNC: func
+          }));
+        }
+      }
+    }
+  };
+};
+
+var _path = require("path");
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildPrerequisiteAssignment = (0, _babelTemplate2.default)("\n  GLOBAL_REFERENCE = GLOBAL_REFERENCE || {}\n");
+
+var buildGlobalExport = (0, _babelTemplate2.default)("\n  var mod = { exports: {} };\n  factory(BROWSER_ARGUMENTS);\n  PREREQUISITE_ASSIGNMENTS\n  GLOBAL_TO_ASSIGN = mod.exports;\n");
+
+var buildWrapper = (0, _babelTemplate2.default)("\n  (function (global, factory) {\n    if (typeof define === \"function\" && define.amd) {\n      define(MODULE_NAME, AMD_ARGUMENTS, factory);\n    } else if (typeof exports !== \"undefined\") {\n      factory(COMMON_ARGUMENTS);\n    } else {\n      GLOBAL_EXPORT\n    }\n  })(this, FUNC);\n");
+
+module.exports = exports["default"];
+},{"babel-plugin-transform-es2015-modules-amd":77,"babel-template":114,"path":522}],81:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  function Property(path, node, scope, getObjectRef, file) {
+    var replaceSupers = new _babelHelperReplaceSupers2.default({
+      getObjectRef: getObjectRef,
+      methodNode: node,
+      methodPath: path,
+      isStatic: true,
+      scope: scope,
+      file: file
+    });
+
+    replaceSupers.replace();
+  }
+
+  var CONTAINS_SUPER = (0, _symbol2.default)();
+
+  return {
+    visitor: {
+      Super: function Super(path) {
+        var parentObj = path.findParent(function (path) {
+          return path.isObjectExpression();
+        });
+        if (parentObj) parentObj.node[CONTAINS_SUPER] = true;
+      },
+
+
+      ObjectExpression: {
+        exit: function exit(path, file) {
+          if (!path.node[CONTAINS_SUPER]) return;
+
+          var objectRef = void 0;
+          var getObjectRef = function getObjectRef() {
+            return objectRef = objectRef || path.scope.generateUidIdentifier("obj");
+          };
+
+          var propPaths = path.get("properties");
+          for (var _iterator = propPaths, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+            var _ref2;
+
+            if (_isArray) {
+              if (_i >= _iterator.length) break;
+              _ref2 = _iterator[_i++];
+            } else {
+              _i = _iterator.next();
+              if (_i.done) break;
+              _ref2 = _i.value;
+            }
+
+            var propPath = _ref2;
+
+            if (propPath.isObjectProperty()) propPath = propPath.get("value");
+            Property(propPath, propPath.node, path.scope, getObjectRef, file);
+          }
+
+          if (objectRef) {
+            path.scope.push({ id: objectRef });
+            path.replaceWith(t.assignmentExpression("=", objectRef, path.node));
+          }
+        }
+      }
+    }
+  };
+};
+
+var _babelHelperReplaceSupers = require("babel-helper-replace-supers");
+
+var _babelHelperReplaceSupers2 = _interopRequireDefault(_babelHelperReplaceSupers);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-helper-replace-supers":58,"babel-runtime/core-js/get-iterator":95,"babel-runtime/core-js/symbol":104}],82:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.visitor = undefined;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _babelHelperGetFunctionArity = require("babel-helper-get-function-arity");
+
+var _babelHelperGetFunctionArity2 = _interopRequireDefault(_babelHelperGetFunctionArity);
+
+var _babelHelperCallDelegate = require("babel-helper-call-delegate");
+
+var _babelHelperCallDelegate2 = _interopRequireDefault(_babelHelperCallDelegate);
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildDefaultParam = (0, _babelTemplate2.default)("\n  let VARIABLE_NAME =\n    ARGUMENTS.length > ARGUMENT_KEY && ARGUMENTS[ARGUMENT_KEY] !== undefined ?\n      ARGUMENTS[ARGUMENT_KEY]\n    :\n      DEFAULT_VALUE;\n");
+
+var buildCutOff = (0, _babelTemplate2.default)("\n  let $0 = $1[$2];\n");
+
+function hasDefaults(node) {
+  for (var _iterator = node.params, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+    var _ref;
+
+    if (_isArray) {
+      if (_i >= _iterator.length) break;
+      _ref = _iterator[_i++];
+    } else {
+      _i = _iterator.next();
+      if (_i.done) break;
+      _ref = _i.value;
+    }
+
+    var param = _ref;
+
+    if (!t.isIdentifier(param)) return true;
+  }
+  return false;
+}
+
+function isSafeBinding(scope, node) {
+  if (!scope.hasOwnBinding(node.name)) return true;
+
+  var _scope$getOwnBinding = scope.getOwnBinding(node.name),
+      kind = _scope$getOwnBinding.kind;
+
+  return kind === "param" || kind === "local";
+}
+
+var iifeVisitor = {
+  ReferencedIdentifier: function ReferencedIdentifier(path, state) {
+    var scope = path.scope,
+        node = path.node;
+
+    if (node.name === "eval" || !isSafeBinding(scope, node)) {
+      state.iife = true;
+      path.stop();
+    }
+  },
+  Scope: function Scope(path) {
+    path.skip();
+  }
+};
+
+var visitor = exports.visitor = {
+  Function: function Function(path) {
+    var node = path.node,
+        scope = path.scope;
+
+    if (!hasDefaults(node)) return;
+
+    path.ensureBlock();
+
+    var state = {
+      iife: false,
+      scope: scope
+    };
+
+    var body = [];
+
+    var argsIdentifier = t.identifier("arguments");
+    argsIdentifier._shadowedFunctionLiteral = path;
+
+    function pushDefNode(left, right, i) {
+      var defNode = buildDefaultParam({
+        VARIABLE_NAME: left,
+        DEFAULT_VALUE: right,
+        ARGUMENT_KEY: t.numericLiteral(i),
+        ARGUMENTS: argsIdentifier
+      });
+      defNode._blockHoist = node.params.length - i;
+      body.push(defNode);
+    }
+
+    var lastNonDefaultParam = (0, _babelHelperGetFunctionArity2.default)(node);
+
+    var params = path.get("params");
+    for (var i = 0; i < params.length; i++) {
+      var param = params[i];
+
+      if (!param.isAssignmentPattern()) {
+        if (!state.iife && !param.isIdentifier()) {
+          param.traverse(iifeVisitor, state);
+        }
+
+        continue;
+      }
+
+      var left = param.get("left");
+      var right = param.get("right");
+
+      if (i >= lastNonDefaultParam || left.isPattern()) {
+        var placeholder = scope.generateUidIdentifier("x");
+        placeholder._isDefaultPlaceholder = true;
+        node.params[i] = placeholder;
+      } else {
+        node.params[i] = left.node;
+      }
+
+      if (!state.iife) {
+        if (right.isIdentifier() && !isSafeBinding(scope, right.node)) {
+          state.iife = true;
+        } else {
+          right.traverse(iifeVisitor, state);
+        }
+      }
+
+      pushDefNode(left.node, right.node, i);
+    }
+
+    for (var _i2 = lastNonDefaultParam + 1; _i2 < node.params.length; _i2++) {
+      var _param = node.params[_i2];
+      if (_param._isDefaultPlaceholder) continue;
+
+      var declar = buildCutOff(_param, argsIdentifier, t.numericLiteral(_i2));
+      declar._blockHoist = node.params.length - _i2;
+      body.push(declar);
+    }
+
+    node.params = node.params.slice(0, lastNonDefaultParam);
+
+    if (state.iife) {
+      body.push((0, _babelHelperCallDelegate2.default)(path, scope));
+      path.set("body", t.blockStatement(body));
+    } else {
+      path.get("body").unshiftContainer("body", body);
+    }
+  }
+};
+},{"babel-helper-call-delegate":51,"babel-helper-get-function-arity":54,"babel-runtime/core-js/get-iterator":95,"babel-template":114,"babel-types":151}],83:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.visitor = undefined;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+var visitor = exports.visitor = {
+  Function: function Function(path) {
+    var params = path.get("params");
+
+    var hoistTweak = t.isRestElement(params[params.length - 1]) ? 1 : 0;
+    var outputParamsLength = params.length - hoistTweak;
+
+    for (var i = 0; i < outputParamsLength; i++) {
+      var param = params[i];
+      if (param.isArrayPattern() || param.isObjectPattern()) {
+        var uid = path.scope.generateUidIdentifier("ref");
+
+        var declar = t.variableDeclaration("let", [t.variableDeclarator(param.node, uid)]);
+        declar._blockHoist = outputParamsLength - i;
+
+        path.ensureBlock();
+        path.get("body").unshiftContainer("body", declar);
+
+        param.replaceWith(uid);
+      }
+    }
+  }
+};
+},{"babel-types":151}],84:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function () {
+  return {
+    visitor: _babelTraverse.visitors.merge([{
+      ArrowFunctionExpression: function ArrowFunctionExpression(path) {
+        var params = path.get("params");
+        for (var _iterator = params, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+          var _ref;
+
+          if (_isArray) {
+            if (_i >= _iterator.length) break;
+            _ref = _iterator[_i++];
+          } else {
+            _i = _iterator.next();
+            if (_i.done) break;
+            _ref = _i.value;
+          }
+
+          var param = _ref;
+
+          if (param.isRestElement() || param.isAssignmentPattern()) {
+            path.arrowFunctionToShadowed();
+            break;
+          }
+        }
+      }
+    }, destructuring.visitor, rest.visitor, def.visitor])
+  };
+};
+
+var _babelTraverse = require("babel-traverse");
+
+var _destructuring = require("./destructuring");
+
+var destructuring = _interopRequireWildcard(_destructuring);
+
+var _default = require("./default");
+
+var def = _interopRequireWildcard(_default);
+
+var _rest = require("./rest");
+
+var rest = _interopRequireWildcard(_rest);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"./default":82,"./destructuring":83,"./rest":85,"babel-runtime/core-js/get-iterator":95,"babel-traverse":118}],85:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.visitor = undefined;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _babelTemplate = require("babel-template");
+
+var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var buildRest = (0, _babelTemplate2.default)("\n  for (var LEN = ARGUMENTS.length,\n           ARRAY = Array(ARRAY_LEN),\n           KEY = START;\n       KEY < LEN;\n       KEY++) {\n    ARRAY[ARRAY_KEY] = ARGUMENTS[KEY];\n  }\n");
+
+var restIndex = (0, _babelTemplate2.default)("\n  ARGUMENTS.length <= INDEX ? undefined : ARGUMENTS[INDEX]\n");
+
+var restIndexImpure = (0, _babelTemplate2.default)("\n  REF = INDEX, ARGUMENTS.length <= REF ? undefined : ARGUMENTS[REF]\n");
+
+var restLength = (0, _babelTemplate2.default)("\n  ARGUMENTS.length <= OFFSET ? 0 : ARGUMENTS.length - OFFSET\n");
+
+var memberExpressionOptimisationVisitor = {
+  Scope: function Scope(path, state) {
+    if (!path.scope.bindingIdentifierEquals(state.name, state.outerBinding)) {
+      path.skip();
+    }
+  },
+  Flow: function Flow(path) {
+    if (path.isTypeCastExpression()) return;
+
+    path.skip();
+  },
+
+
+  "Function|ClassProperty": function FunctionClassProperty(path, state) {
+    var oldNoOptimise = state.noOptimise;
+    state.noOptimise = true;
+    path.traverse(memberExpressionOptimisationVisitor, state);
+    state.noOptimise = oldNoOptimise;
+
+    path.skip();
+  },
+
+  ReferencedIdentifier: function ReferencedIdentifier(path, state) {
+    var node = path.node;
+
+    if (node.name === "arguments") {
+      state.deopted = true;
+    }
+
+    if (node.name !== state.name) return;
+
+    if (state.noOptimise) {
+      state.deopted = true;
+    } else {
+      var parentPath = path.parentPath;
+
+      if (parentPath.listKey === "params" && parentPath.key < state.offset) {
+        return;
+      }
+
+      if (parentPath.isMemberExpression({ object: node })) {
+        var grandparentPath = parentPath.parentPath;
+
+        var argsOptEligible = !state.deopted && !(grandparentPath.isAssignmentExpression() && parentPath.node === grandparentPath.node.left || grandparentPath.isLVal() || grandparentPath.isForXStatement() || grandparentPath.isUpdateExpression() || grandparentPath.isUnaryExpression({ operator: "delete" }) || (grandparentPath.isCallExpression() || grandparentPath.isNewExpression()) && parentPath.node === grandparentPath.node.callee);
+
+        if (argsOptEligible) {
+          if (parentPath.node.computed) {
+            if (parentPath.get("property").isBaseType("number")) {
+              state.candidates.push({ cause: "indexGetter", path: path });
+              return;
+            }
+          } else if (parentPath.node.property.name === "length") {
+              state.candidates.push({ cause: "lengthGetter", path: path });
+              return;
+            }
+        }
+      }
+
+      if (state.offset === 0 && parentPath.isSpreadElement()) {
+        var call = parentPath.parentPath;
+        if (call.isCallExpression() && call.node.arguments.length === 1) {
+          state.candidates.push({ cause: "argSpread", path: path });
+          return;
+        }
+      }
+
+      state.references.push(path);
+    }
+  },
+  BindingIdentifier: function BindingIdentifier(_ref, state) {
+    var node = _ref.node;
+
+    if (node.name === state.name) {
+      state.deopted = true;
+    }
+  }
+};
+function hasRest(node) {
+  return t.isRestElement(node.params[node.params.length - 1]);
+}
+
+function optimiseIndexGetter(path, argsId, offset) {
+  var index = void 0;
+
+  if (t.isNumericLiteral(path.parent.property)) {
+    index = t.numericLiteral(path.parent.property.value + offset);
+  } else if (offset === 0) {
+    index = path.parent.property;
+  } else {
+    index = t.binaryExpression("+", path.parent.property, t.numericLiteral(offset));
+  }
+
+  var scope = path.scope;
+
+  if (!scope.isPure(index)) {
+    var temp = scope.generateUidIdentifierBasedOnNode(index);
+    scope.push({ id: temp, kind: "var" });
+    path.parentPath.replaceWith(restIndexImpure({
+      ARGUMENTS: argsId,
+      INDEX: index,
+      REF: temp
+    }));
+  } else {
+    path.parentPath.replaceWith(restIndex({
+      ARGUMENTS: argsId,
+      INDEX: index
+    }));
+  }
+}
+
+function optimiseLengthGetter(path, argsId, offset) {
+  if (offset) {
+    path.parentPath.replaceWith(restLength({
+      ARGUMENTS: argsId,
+      OFFSET: t.numericLiteral(offset)
+    }));
+  } else {
+    path.replaceWith(argsId);
+  }
+}
+
+var visitor = exports.visitor = {
+  Function: function Function(path) {
+    var node = path.node,
+        scope = path.scope;
+
+    if (!hasRest(node)) return;
+
+    var rest = node.params.pop().argument;
+
+    var argsId = t.identifier("arguments");
+
+    argsId._shadowedFunctionLiteral = path;
+
+    var state = {
+      references: [],
+      offset: node.params.length,
+
+      argumentsNode: argsId,
+      outerBinding: scope.getBindingIdentifier(rest.name),
+
+      candidates: [],
+
+      name: rest.name,
+
+      deopted: false
+    };
+
+    path.traverse(memberExpressionOptimisationVisitor, state);
+
+    if (!state.deopted && !state.references.length) {
+      for (var _iterator = state.candidates, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+        var _ref3;
+
+        if (_isArray) {
+          if (_i >= _iterator.length) break;
+          _ref3 = _iterator[_i++];
+        } else {
+          _i = _iterator.next();
+          if (_i.done) break;
+          _ref3 = _i.value;
+        }
+
+        var _ref4 = _ref3;
+        var _path = _ref4.path,
+            cause = _ref4.cause;
+
+        switch (cause) {
+          case "indexGetter":
+            optimiseIndexGetter(_path, argsId, state.offset);
+            break;
+          case "lengthGetter":
+            optimiseLengthGetter(_path, argsId, state.offset);
+            break;
+          default:
+            _path.replaceWith(argsId);
+        }
+      }
+      return;
+    }
+
+    state.references = state.references.concat(state.candidates.map(function (_ref5) {
+      var path = _ref5.path;
+      return path;
+    }));
+
+    state.deopted = state.deopted || !!node.shadow;
+
+    var start = t.numericLiteral(node.params.length);
+    var key = scope.generateUidIdentifier("key");
+    var len = scope.generateUidIdentifier("len");
+
+    var arrKey = key;
+    var arrLen = len;
+    if (node.params.length) {
+      arrKey = t.binaryExpression("-", key, start);
+
+      arrLen = t.conditionalExpression(t.binaryExpression(">", len, start), t.binaryExpression("-", len, start), t.numericLiteral(0));
+    }
+
+    var loop = buildRest({
+      ARGUMENTS: argsId,
+      ARRAY_KEY: arrKey,
+      ARRAY_LEN: arrLen,
+      START: start,
+      ARRAY: rest,
+      KEY: key,
+      LEN: len
+    });
+
+    if (state.deopted) {
+      loop._blockHoist = node.params.length + 1;
+      node.body.body.unshift(loop);
+    } else {
+      loop._blockHoist = 1;
+
+      var target = path.getEarliestCommonAncestorFrom(state.references).getStatementParent();
+
+      target.findParent(function (path) {
+        if (path.isLoop()) {
+          target = path;
+        } else {
+          return path.isFunction();
+        }
+      });
+
+      target.insertBefore(loop);
+    }
+  }
+};
+},{"babel-runtime/core-js/get-iterator":95,"babel-template":114,"babel-types":151}],86:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function () {
+  return {
+    visitor: {
+      ObjectMethod: function ObjectMethod(path) {
+        var node = path.node;
+
+        if (node.kind === "method") {
+          var func = t.functionExpression(null, node.params, node.body, node.generator, node.async);
+          func.returnType = node.returnType;
+
+          path.replaceWith(t.objectProperty(node.key, func, node.computed));
+        }
+      },
+      ObjectProperty: function ObjectProperty(_ref) {
+        var node = _ref.node;
+
+        if (node.shorthand) {
+          node.shorthand = false;
+        }
+      }
+    }
+  };
+};
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+module.exports = exports["default"];
+},{"babel-types":151}],87:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  function getSpreadLiteral(spread, scope, state) {
+    if (state.opts.loose && !t.isIdentifier(spread.argument, { name: "arguments" })) {
+      return spread.argument;
+    } else {
+      return scope.toArray(spread.argument, true);
+    }
+  }
+
+  function hasSpread(nodes) {
+    for (var i = 0; i < nodes.length; i++) {
+      if (t.isSpreadElement(nodes[i])) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  function build(props, scope, state) {
+    var nodes = [];
+
+    var _props = [];
+
+    function push() {
+      if (!_props.length) return;
+      nodes.push(t.arrayExpression(_props));
+      _props = [];
+    }
+
+    for (var _iterator = props, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref2;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref2 = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref2 = _i.value;
+      }
+
+      var prop = _ref2;
+
+      if (t.isSpreadElement(prop)) {
+        push();
+        nodes.push(getSpreadLiteral(prop, scope, state));
+      } else {
+        _props.push(prop);
+      }
+    }
+
+    push();
+
+    return nodes;
+  }
+
+  return {
+    visitor: {
+      ArrayExpression: function ArrayExpression(path, state) {
+        var node = path.node,
+            scope = path.scope;
+
+        var elements = node.elements;
+        if (!hasSpread(elements)) return;
+
+        var nodes = build(elements, scope, state);
+        var first = nodes.shift();
+
+        if (!t.isArrayExpression(first)) {
+          nodes.unshift(first);
+          first = t.arrayExpression([]);
+        }
+
+        path.replaceWith(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
+      },
+      CallExpression: function CallExpression(path, state) {
+        var node = path.node,
+            scope = path.scope;
+
+
+        var args = node.arguments;
+        if (!hasSpread(args)) return;
+
+        var calleePath = path.get("callee");
+        if (calleePath.isSuper()) return;
+
+        var contextLiteral = t.identifier("undefined");
+
+        node.arguments = [];
+
+        var nodes = void 0;
+        if (args.length === 1 && args[0].argument.name === "arguments") {
+          nodes = [args[0].argument];
+        } else {
+          nodes = build(args, scope, state);
+        }
+
+        var first = nodes.shift();
+        if (nodes.length) {
+          node.arguments.push(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
+        } else {
+          node.arguments.push(first);
+        }
+
+        var callee = node.callee;
+
+        if (calleePath.isMemberExpression()) {
+          var temp = scope.maybeGenerateMemoised(callee.object);
+          if (temp) {
+            callee.object = t.assignmentExpression("=", temp, callee.object);
+            contextLiteral = temp;
+          } else {
+            contextLiteral = callee.object;
+          }
+          t.appendToMemberExpression(callee, t.identifier("apply"));
+        } else {
+          node.callee = t.memberExpression(node.callee, t.identifier("apply"));
+        }
+
+        if (t.isSuper(contextLiteral)) {
+          contextLiteral = t.thisExpression();
+        }
+
+        node.arguments.unshift(contextLiteral);
+      },
+      NewExpression: function NewExpression(path, state) {
+        var node = path.node,
+            scope = path.scope;
+
+        var args = node.arguments;
+        if (!hasSpread(args)) return;
+
+        var nodes = build(args, scope, state);
+
+        var context = t.arrayExpression([t.nullLiteral()]);
+
+        args = t.callExpression(t.memberExpression(context, t.identifier("concat")), nodes);
+
+        path.replaceWith(t.newExpression(t.callExpression(t.memberExpression(t.memberExpression(t.memberExpression(t.identifier("Function"), t.identifier("prototype")), t.identifier("bind")), t.identifier("apply")), [node.callee, args]), []));
+      }
+    }
+  };
+};
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95}],88:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function () {
+  return {
+    visitor: {
+      RegExpLiteral: function RegExpLiteral(path) {
+        var node = path.node;
+
+        if (!regex.is(node, "y")) return;
+
+        path.replaceWith(t.newExpression(t.identifier("RegExp"), [t.stringLiteral(node.pattern), t.stringLiteral(node.flags)]));
+      }
+    }
+  };
+};
+
+var _babelHelperRegex = require("babel-helper-regex");
+
+var regex = _interopRequireWildcard(_babelHelperRegex);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+module.exports = exports["default"];
+},{"babel-helper-regex":57,"babel-types":151}],89:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  function isString(node) {
+    return t.isLiteral(node) && typeof node.value === "string";
+  }
+
+  function buildBinaryExpression(left, right) {
+    return t.binaryExpression("+", left, right);
+  }
+
+  return {
+    visitor: {
+      TaggedTemplateExpression: function TaggedTemplateExpression(path, state) {
+        var node = path.node;
+
+        var quasi = node.quasi;
+        var args = [];
+
+        var strings = [];
+        var raw = [];
+
+        for (var _iterator = quasi.quasis, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+          var _ref2;
+
+          if (_isArray) {
+            if (_i >= _iterator.length) break;
+            _ref2 = _iterator[_i++];
+          } else {
+            _i = _iterator.next();
+            if (_i.done) break;
+            _ref2 = _i.value;
+          }
+
+          var elem = _ref2;
+
+          strings.push(t.stringLiteral(elem.value.cooked));
+          raw.push(t.stringLiteral(elem.value.raw));
+        }
+
+        strings = t.arrayExpression(strings);
+        raw = t.arrayExpression(raw);
+
+        var templateName = "taggedTemplateLiteral";
+        if (state.opts.loose) templateName += "Loose";
+
+        var templateObject = state.file.addTemplateObject(templateName, strings, raw);
+        args.push(templateObject);
+
+        args = args.concat(quasi.expressions);
+
+        path.replaceWith(t.callExpression(node.tag, args));
+      },
+      TemplateLiteral: function TemplateLiteral(path, state) {
+        var nodes = [];
+
+        var expressions = path.get("expressions");
+
+        for (var _iterator2 = path.node.quasis, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+          var _ref3;
+
+          if (_isArray2) {
+            if (_i2 >= _iterator2.length) break;
+            _ref3 = _iterator2[_i2++];
+          } else {
+            _i2 = _iterator2.next();
+            if (_i2.done) break;
+            _ref3 = _i2.value;
+          }
+
+          var elem = _ref3;
+
+          nodes.push(t.stringLiteral(elem.value.cooked));
+
+          var expr = expressions.shift();
+          if (expr) {
+            if (state.opts.spec && !expr.isBaseType("string") && !expr.isBaseType("number")) {
+              nodes.push(t.callExpression(t.identifier("String"), [expr.node]));
+            } else {
+              nodes.push(expr.node);
+            }
+          }
+        }
+
+        nodes = nodes.filter(function (n) {
+          return !t.isLiteral(n, { value: "" });
+        });
+
+        if (!isString(nodes[0]) && !isString(nodes[1])) {
+          nodes.unshift(t.stringLiteral(""));
+        }
+
+        if (nodes.length > 1) {
+          var root = buildBinaryExpression(nodes.shift(), nodes.shift());
+
+          for (var _iterator3 = nodes, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+            var _ref4;
+
+            if (_isArray3) {
+              if (_i3 >= _iterator3.length) break;
+              _ref4 = _iterator3[_i3++];
+            } else {
+              _i3 = _iterator3.next();
+              if (_i3.done) break;
+              _ref4 = _i3.value;
+            }
+
+            var node = _ref4;
+
+            root = buildBinaryExpression(root, node);
+          }
+
+          path.replaceWith(root);
+        } else {
+          path.replaceWith(nodes[0]);
+        }
+      }
+    }
+  };
+};
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95}],90:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+exports.default = function (_ref) {
+  var t = _ref.types;
+
+  var IGNORE = (0, _symbol2.default)();
+
+  return {
+    visitor: {
+      Scope: function Scope(_ref2) {
+        var scope = _ref2.scope;
+
+        if (!scope.getBinding("Symbol")) {
+          return;
+        }
+
+        scope.rename("Symbol");
+      },
+      UnaryExpression: function UnaryExpression(path) {
+        var node = path.node,
+            parent = path.parent;
+
+        if (node[IGNORE]) return;
+        if (path.find(function (path) {
+          return path.node && !!path.node._generated;
+        })) return;
+
+        if (path.parentPath.isBinaryExpression() && t.EQUALITY_BINARY_OPERATORS.indexOf(parent.operator) >= 0) {
+          var opposite = path.getOpposite();
+          if (opposite.isLiteral() && opposite.node.value !== "symbol" && opposite.node.value !== "object") {
+            return;
+          }
+        }
+
+        if (node.operator === "typeof") {
+          var call = t.callExpression(this.addHelper("typeof"), [node.argument]);
+          if (path.get("argument").isIdentifier()) {
+            var undefLiteral = t.stringLiteral("undefined");
+            var unary = t.unaryExpression("typeof", node.argument);
+            unary[IGNORE] = true;
+            path.replaceWith(t.conditionalExpression(t.binaryExpression("===", unary, undefLiteral), undefLiteral, call));
+          } else {
+            path.replaceWith(call);
+          }
+        }
+      }
+    }
+  };
+};
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/symbol":104}],91:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function () {
+  return {
+    visitor: {
+      RegExpLiteral: function RegExpLiteral(_ref) {
+        var node = _ref.node;
+
+        if (!regex.is(node, "u")) return;
+        node.pattern = (0, _regexpuCore2.default)(node.pattern, node.flags);
+        regex.pullFlag(node, "u");
+      }
+    }
+  };
+};
+
+var _regexpuCore = require("regexpu-core");
+
+var _regexpuCore2 = _interopRequireDefault(_regexpuCore);
+
+var _babelHelperRegex = require("babel-helper-regex");
+
+var regex = _interopRequireWildcard(_babelHelperRegex);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-helper-regex":57,"regexpu-core":537}],92:[function(require,module,exports){
+"use strict";
+
+module.exports = require("regenerator-transform");
+},{"regenerator-transform":529}],93:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.default = function () {
+  return {
+    visitor: {
+      Program: function Program(path, state) {
+        if (state.opts.strict === false || state.opts.strictMode === false) return;
+
+        var node = path.node;
+
+
+        for (var _iterator = node.directives, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+          var _ref;
+
+          if (_isArray) {
+            if (_i >= _iterator.length) break;
+            _ref = _iterator[_i++];
+          } else {
+            _i = _iterator.next();
+            if (_i.done) break;
+            _ref = _i.value;
+          }
+
+          var directive = _ref;
+
+          if (directive.value.value === "use strict") return;
+        }
+
+        path.unshiftContainer("directives", t.directive(t.directiveLiteral("use strict")));
+      }
+    }
+  };
+};
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = exports["default"];
+},{"babel-runtime/core-js/get-iterator":95,"babel-types":151}],94:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _babelPluginTransformEs2015TemplateLiterals = require("babel-plugin-transform-es2015-template-literals");
+
+var _babelPluginTransformEs2015TemplateLiterals2 = _interopRequireDefault(_babelPluginTransformEs2015TemplateLiterals);
+
+var _babelPluginTransformEs2015Literals = require("babel-plugin-transform-es2015-literals");
+
+var _babelPluginTransformEs2015Literals2 = _interopRequireDefault(_babelPluginTransformEs2015Literals);
+
+var _babelPluginTransformEs2015FunctionName = require("babel-plugin-transform-es2015-function-name");
+
+var _babelPluginTransformEs2015FunctionName2 = _interopRequireDefault(_babelPluginTransformEs2015FunctionName);
+
+var _babelPluginTransformEs2015ArrowFunctions = require("babel-plugin-transform-es2015-arrow-functions");
+
+var _babelPluginTransformEs2015ArrowFunctions2 = _interopRequireDefault(_babelPluginTransformEs2015ArrowFunctions);
+
+var _babelPluginTransformEs2015BlockScopedFunctions = require("babel-plugin-transform-es2015-block-scoped-functions");
+
+var _babelPluginTransformEs2015BlockScopedFunctions2 = _interopRequireDefault(_babelPluginTransformEs2015BlockScopedFunctions);
+
+var _babelPluginTransformEs2015Classes = require("babel-plugin-transform-es2015-classes");
+
+var _babelPluginTransformEs2015Classes2 = _interopRequireDefault(_babelPluginTransformEs2015Classes);
+
+var _babelPluginTransformEs2015ObjectSuper = require("babel-plugin-transform-es2015-object-super");
+
+var _babelPluginTransformEs2015ObjectSuper2 = _interopRequireDefault(_babelPluginTransformEs2015ObjectSuper);
+
+var _babelPluginTransformEs2015ShorthandProperties = require("babel-plugin-transform-es2015-shorthand-properties");
+
+var _babelPluginTransformEs2015ShorthandProperties2 = _interopRequireDefault(_babelPluginTransformEs2015ShorthandProperties);
+
+var _babelPluginTransformEs2015DuplicateKeys = require("babel-plugin-transform-es2015-duplicate-keys");
+
+var _babelPluginTransformEs2015DuplicateKeys2 = _interopRequireDefault(_babelPluginTransformEs2015DuplicateKeys);
+
+var _babelPluginTransformEs2015ComputedProperties = require("babel-plugin-transform-es2015-computed-properties");
+
+var _babelPluginTransformEs2015ComputedProperties2 = _interopRequireDefault(_babelPluginTransformEs2015ComputedProperties);
+
+var _babelPluginTransformEs2015ForOf = require("babel-plugin-transform-es2015-for-of");
+
+var _babelPluginTransformEs2015ForOf2 = _interopRequireDefault(_babelPluginTransformEs2015ForOf);
+
+var _babelPluginTransformEs2015StickyRegex = require("babel-plugin-transform-es2015-sticky-regex");
+
+var _babelPluginTransformEs2015StickyRegex2 = _interopRequireDefault(_babelPluginTransformEs2015StickyRegex);
+
+var _babelPluginTransformEs2015UnicodeRegex = require("babel-plugin-transform-es2015-unicode-regex");
+
+var _babelPluginTransformEs2015UnicodeRegex2 = _interopRequireDefault(_babelPluginTransformEs2015UnicodeRegex);
+
+var _babelPluginCheckEs2015Constants = require("babel-plugin-check-es2015-constants");
+
+var _babelPluginCheckEs2015Constants2 = _interopRequireDefault(_babelPluginCheckEs2015Constants);
+
+var _babelPluginTransformEs2015Spread = require("babel-plugin-transform-es2015-spread");
+
+var _babelPluginTransformEs2015Spread2 = _interopRequireDefault(_babelPluginTransformEs2015Spread);
+
+var _babelPluginTransformEs2015Parameters = require("babel-plugin-transform-es2015-parameters");
+
+var _babelPluginTransformEs2015Parameters2 = _interopRequireDefault(_babelPluginTransformEs2015Parameters);
+
+var _babelPluginTransformEs2015Destructuring = require("babel-plugin-transform-es2015-destructuring");
+
+var _babelPluginTransformEs2015Destructuring2 = _interopRequireDefault(_babelPluginTransformEs2015Destructuring);
+
+var _babelPluginTransformEs2015BlockScoping = require("babel-plugin-transform-es2015-block-scoping");
+
+var _babelPluginTransformEs2015BlockScoping2 = _interopRequireDefault(_babelPluginTransformEs2015BlockScoping);
+
+var _babelPluginTransformEs2015TypeofSymbol = require("babel-plugin-transform-es2015-typeof-symbol");
+
+var _babelPluginTransformEs2015TypeofSymbol2 = _interopRequireDefault(_babelPluginTransformEs2015TypeofSymbol);
+
+var _babelPluginTransformEs2015ModulesCommonjs = require("babel-plugin-transform-es2015-modules-commonjs");
+
+var _babelPluginTransformEs2015ModulesCommonjs2 = _interopRequireDefault(_babelPluginTransformEs2015ModulesCommonjs);
+
+var _babelPluginTransformEs2015ModulesSystemjs = require("babel-plugin-transform-es2015-modules-systemjs");
+
+var _babelPluginTransformEs2015ModulesSystemjs2 = _interopRequireDefault(_babelPluginTransformEs2015ModulesSystemjs);
+
+var _babelPluginTransformEs2015ModulesAmd = require("babel-plugin-transform-es2015-modules-amd");
+
+var _babelPluginTransformEs2015ModulesAmd2 = _interopRequireDefault(_babelPluginTransformEs2015ModulesAmd);
+
+var _babelPluginTransformEs2015ModulesUmd = require("babel-plugin-transform-es2015-modules-umd");
+
+var _babelPluginTransformEs2015ModulesUmd2 = _interopRequireDefault(_babelPluginTransformEs2015ModulesUmd);
+
+var _babelPluginTransformRegenerator = require("babel-plugin-transform-regenerator");
+
+var _babelPluginTransformRegenerator2 = _interopRequireDefault(_babelPluginTransformRegenerator);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function preset(context) {
+  var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+  var moduleTypes = ["commonjs", "amd", "umd", "systemjs"];
+  var loose = false;
+  var modules = "commonjs";
+  var spec = false;
+
+  if (opts !== undefined) {
+    if (opts.loose !== undefined) loose = opts.loose;
+    if (opts.modules !== undefined) modules = opts.modules;
+    if (opts.spec !== undefined) spec = opts.spec;
+  }
+
+  if (typeof loose !== "boolean") throw new Error("Preset es2015 'loose' option must be a boolean.");
+  if (typeof spec !== "boolean") throw new Error("Preset es2015 'spec' option must be a boolean.");
+  if (modules !== false && moduleTypes.indexOf(modules) === -1) {
+    throw new Error("Preset es2015 'modules' option must be 'false' to indicate no modules\n" + "or a module type which be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'");
+  }
+
+  var optsLoose = { loose: loose };
+
+  return {
+    plugins: [[_babelPluginTransformEs2015TemplateLiterals2.default, { loose: loose, spec: spec }], _babelPluginTransformEs2015Literals2.default, _babelPluginTransformEs2015FunctionName2.default, [_babelPluginTransformEs2015ArrowFunctions2.default, { spec: spec }], _babelPluginTransformEs2015BlockScopedFunctions2.default, [_babelPluginTransformEs2015Classes2.default, optsLoose], _babelPluginTransformEs2015ObjectSuper2.default, _babelPluginTransformEs2015ShorthandProperties2.default, _babelPluginTransformEs2015DuplicateKeys2.default, [_babelPluginTransformEs2015ComputedProperties2.default, optsLoose], [_babelPluginTransformEs2015ForOf2.default, optsLoose], _babelPluginTransformEs2015StickyRegex2.default, _babelPluginTransformEs2015UnicodeRegex2.default, _babelPluginCheckEs2015Constants2.default, [_babelPluginTransformEs2015Spread2.default, optsLoose], _babelPluginTransformEs2015Parameters2.default, [_babelPluginTransformEs2015Destructuring2.default, optsLoose], _babelPluginTransformEs2015BlockScoping2.default, _babelPluginTransformEs2015TypeofSymbol2.default, modules === "commonjs" && [_babelPluginTransformEs2015ModulesCommonjs2.default, optsLoose], modules === "systemjs" && [_babelPluginTransformEs2015ModulesSystemjs2.default, optsLoose], modules === "amd" && [_babelPluginTransformEs2015ModulesAmd2.default, optsLoose], modules === "umd" && [_babelPluginTransformEs2015ModulesUmd2.default, optsLoose], [_babelPluginTransformRegenerator2.default, { async: false, asyncGenerators: false }]].filter(Boolean) };
+}
+
+var oldConfig = preset({});
+
+exports.default = oldConfig;
+
+Object.defineProperty(oldConfig, "buildPreset", {
+  configurable: true,
+  writable: true,
+
+  enumerable: false,
+  value: preset
+});
+module.exports = exports["default"];
+},{"babel-plugin-check-es2015-constants":62,"babel-plugin-transform-es2015-arrow-functions":64,"babel-plugin-transform-es2015-block-scoped-functions":65,"babel-plugin-transform-es2015-block-scoping":66,"babel-plugin-transform-es2015-classes":68,"babel-plugin-transform-es2015-computed-properties":71,"babel-plugin-transform-es2015-destructuring":72,"babel-plugin-transform-es2015-duplicate-keys":73,"babel-plugin-transform-es2015-for-of":74,"babel-plugin-transform-es2015-function-name":75,"babel-plugin-transform-es2015-literals":76,"babel-plugin-transform-es2015-modules-amd":77,"babel-plugin-transform-es2015-modules-commonjs":78,"babel-plugin-transform-es2015-modules-systemjs":79,"babel-plugin-transform-es2015-modules-umd":80,"babel-plugin-transform-es2015-object-super":81,"babel-plugin-transform-es2015-parameters":84,"babel-plugin-transform-es2015-shorthand-properties":86,"babel-plugin-transform-es2015-spread":87,"babel-plugin-transform-es2015-sticky-regex":88,"babel-plugin-transform-es2015-template-literals":89,"babel-plugin-transform-es2015-typeof-symbol":90,"babel-plugin-transform-es2015-unicode-regex":91,"babel-plugin-transform-regenerator":92}],95:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/get-iterator"), __esModule: true };
+},{"core-js/library/fn/get-iterator":164}],96:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/json/stringify"), __esModule: true };
+},{"core-js/library/fn/json/stringify":165}],97:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/map"), __esModule: true };
+},{"core-js/library/fn/map":166}],98:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/number/max-safe-integer"), __esModule: true };
+},{"core-js/library/fn/number/max-safe-integer":167}],99:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/object/assign"), __esModule: true };
+},{"core-js/library/fn/object/assign":168}],100:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/object/create"), __esModule: true };
+},{"core-js/library/fn/object/create":169}],101:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/object/get-own-property-symbols"), __esModule: true };
+},{"core-js/library/fn/object/get-own-property-symbols":170}],102:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/object/keys"), __esModule: true };
+},{"core-js/library/fn/object/keys":171}],103:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/object/set-prototype-of"), __esModule: true };
+},{"core-js/library/fn/object/set-prototype-of":172}],104:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/symbol"), __esModule: true };
+},{"core-js/library/fn/symbol":174}],105:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/symbol/for"), __esModule: true };
+},{"core-js/library/fn/symbol/for":173}],106:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/symbol/iterator"), __esModule: true };
+},{"core-js/library/fn/symbol/iterator":175}],107:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/weak-map"), __esModule: true };
+},{"core-js/library/fn/weak-map":176}],108:[function(require,module,exports){
+module.exports = { "default": require("core-js/library/fn/weak-set"), __esModule: true };
+},{"core-js/library/fn/weak-set":177}],109:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (instance, Constructor) {
+  if (!(instance instanceof Constructor)) {
+    throw new TypeError("Cannot call a class as a function");
+  }
+};
+},{}],110:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _setPrototypeOf = require("../core-js/object/set-prototype-of");
+
+var _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf);
+
+var _create = require("../core-js/object/create");
+
+var _create2 = _interopRequireDefault(_create);
+
+var _typeof2 = require("../helpers/typeof");
+
+var _typeof3 = _interopRequireDefault(_typeof2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = function (subClass, superClass) {
+  if (typeof superClass !== "function" && superClass !== null) {
+    throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : (0, _typeof3.default)(superClass)));
+  }
+
+  subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, {
+    constructor: {
+      value: subClass,
+      enumerable: false,
+      writable: true,
+      configurable: true
+    }
+  });
+  if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass;
+};
+},{"../core-js/object/create":100,"../core-js/object/set-prototype-of":103,"../helpers/typeof":113}],111:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+exports.default = function (obj, keys) {
+  var target = {};
+
+  for (var i in obj) {
+    if (keys.indexOf(i) >= 0) continue;
+    if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
+    target[i] = obj[i];
+  }
+
+  return target;
+};
+},{}],112:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _typeof2 = require("../helpers/typeof");
+
+var _typeof3 = _interopRequireDefault(_typeof2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = function (self, call) {
+  if (!self) {
+    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+  }
+
+  return call && ((typeof call === "undefined" ? "undefined" : (0, _typeof3.default)(call)) === "object" || typeof call === "function") ? call : self;
+};
+},{"../helpers/typeof":113}],113:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _iterator = require("../core-js/symbol/iterator");
+
+var _iterator2 = _interopRequireDefault(_iterator);
+
+var _symbol = require("../core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+var _typeof = typeof _symbol2.default === "function" && typeof _iterator2.default === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj; };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = typeof _symbol2.default === "function" && _typeof(_iterator2.default) === "symbol" ? function (obj) {
+  return typeof obj === "undefined" ? "undefined" : _typeof(obj);
+} : function (obj) {
+  return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof(obj);
+};
+},{"../core-js/symbol":104,"../core-js/symbol/iterator":106}],114:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _symbol = require("babel-runtime/core-js/symbol");
+
+var _symbol2 = _interopRequireDefault(_symbol);
+
+exports.default = function (code, opts) {
+  var stack = void 0;
+  try {
+    throw new Error();
+  } catch (error) {
+    if (error.stack) {
+      stack = error.stack.split("\n").slice(1).join("\n");
+    }
+  }
+
+  opts = (0, _assign2.default)({
+    allowReturnOutsideFunction: true,
+    allowSuperOutsideMethod: true,
+    preserveComments: false
+  }, opts);
+
+  var _getAst = function getAst() {
+    var ast = void 0;
+
+    try {
+      ast = babylon.parse(code, opts);
+
+      ast = _babelTraverse2.default.removeProperties(ast, { preserveComments: opts.preserveComments });
+
+      _babelTraverse2.default.cheap(ast, function (node) {
+        node[FROM_TEMPLATE] = true;
+      });
+    } catch (err) {
+      err.stack = err.stack + "from\n" + stack;
+      throw err;
+    }
+
+    _getAst = function getAst() {
+      return ast;
+    };
+
+    return ast;
+  };
+
+  return function () {
+    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
+    }
+
+    return useTemplate(_getAst(), args);
+  };
+};
+
+var _cloneDeep = require("lodash/cloneDeep");
+
+var _cloneDeep2 = _interopRequireDefault(_cloneDeep);
+
+var _assign = require("lodash/assign");
+
+var _assign2 = _interopRequireDefault(_assign);
+
+var _has = require("lodash/has");
+
+var _has2 = _interopRequireDefault(_has);
+
+var _babelTraverse = require("babel-traverse");
+
+var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
+
+var _babylon = require("babylon");
+
+var babylon = _interopRequireWildcard(_babylon);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var FROM_TEMPLATE = "_fromTemplate";
+var TEMPLATE_SKIP = (0, _symbol2.default)();
+
+function useTemplate(ast, nodes) {
+  ast = (0, _cloneDeep2.default)(ast);
+  var _ast = ast,
+      program = _ast.program;
+
+
+  if (nodes.length) {
+    (0, _babelTraverse2.default)(ast, templateVisitor, null, nodes);
+  }
+
+  if (program.body.length > 1) {
+    return program.body;
+  } else {
+    return program.body[0];
+  }
+}
+
+var templateVisitor = {
+  noScope: true,
+
+  enter: function enter(path, args) {
+    var node = path.node;
+
+    if (node[TEMPLATE_SKIP]) return path.skip();
+
+    if (t.isExpressionStatement(node)) {
+      node = node.expression;
+    }
+
+    var replacement = void 0;
+
+    if (t.isIdentifier(node) && node[FROM_TEMPLATE]) {
+      if ((0, _has2.default)(args[0], node.name)) {
+        replacement = args[0][node.name];
+      } else if (node.name[0] === "$") {
+        var i = +node.name.slice(1);
+        if (args[i]) replacement = args[i];
+      }
+    }
+
+    if (replacement === null) {
+      path.remove();
+    }
+
+    if (replacement) {
+      replacement[TEMPLATE_SKIP] = true;
+      path.replaceInline(replacement);
+    }
+  },
+  exit: function exit(_ref) {
+    var node = _ref.node;
+
+    if (!node.loc) _babelTraverse2.default.clearNode(node);
+  }
+};
+module.exports = exports["default"];
+},{"babel-runtime/core-js/symbol":104,"babel-traverse":118,"babel-types":151,"babylon":155,"lodash/assign":463,"lodash/cloneDeep":467,"lodash/has":479}],115:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.scope = exports.path = undefined;
+
+var _weakMap = require("babel-runtime/core-js/weak-map");
+
+var _weakMap2 = _interopRequireDefault(_weakMap);
+
+exports.clear = clear;
+exports.clearPath = clearPath;
+exports.clearScope = clearScope;
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var path = exports.path = new _weakMap2.default();
+var scope = exports.scope = new _weakMap2.default();
+
+function clear() {
+  clearPath();
+  clearScope();
+}
+
+function clearPath() {
+  exports.path = path = new _weakMap2.default();
+}
+
+function clearScope() {
+  exports.scope = scope = new _weakMap2.default();
+}
+},{"babel-runtime/core-js/weak-map":107}],116:[function(require,module,exports){
+(function (process){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _path2 = require("./path");
+
+var _path3 = _interopRequireDefault(_path2);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var testing = process.env.NODE_ENV === "test";
+
+var TraversalContext = function () {
+  function TraversalContext(scope, opts, state, parentPath) {
+    (0, _classCallCheck3.default)(this, TraversalContext);
+    this.queue = null;
+
+    this.parentPath = parentPath;
+    this.scope = scope;
+    this.state = state;
+    this.opts = opts;
+  }
+
+  TraversalContext.prototype.shouldVisit = function shouldVisit(node) {
+    var opts = this.opts;
+    if (opts.enter || opts.exit) return true;
+
+    if (opts[node.type]) return true;
+
+    var keys = t.VISITOR_KEYS[node.type];
+    if (!keys || !keys.length) return false;
+
+    for (var _iterator = keys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var key = _ref;
+
+      if (node[key]) return true;
+    }
+
+    return false;
+  };
+
+  TraversalContext.prototype.create = function create(node, obj, key, listKey) {
+    return _path3.default.get({
+      parentPath: this.parentPath,
+      parent: node,
+      container: obj,
+      key: key,
+      listKey: listKey
+    });
+  };
+
+  TraversalContext.prototype.maybeQueue = function maybeQueue(path, notPriority) {
+    if (this.trap) {
+      throw new Error("Infinite cycle detected");
+    }
+
+    if (this.queue) {
+      if (notPriority) {
+        this.queue.push(path);
+      } else {
+        this.priorityQueue.push(path);
+      }
+    }
+  };
+
+  TraversalContext.prototype.visitMultiple = function visitMultiple(container, parent, listKey) {
+    if (container.length === 0) return false;
+
+    var queue = [];
+
+    for (var key = 0; key < container.length; key++) {
+      var node = container[key];
+      if (node && this.shouldVisit(node)) {
+        queue.push(this.create(parent, container, key, listKey));
+      }
+    }
+
+    return this.visitQueue(queue);
+  };
+
+  TraversalContext.prototype.visitSingle = function visitSingle(node, key) {
+    if (this.shouldVisit(node[key])) {
+      return this.visitQueue([this.create(node, node, key)]);
+    } else {
+      return false;
+    }
+  };
+
+  TraversalContext.prototype.visitQueue = function visitQueue(queue) {
+    this.queue = queue;
+    this.priorityQueue = [];
+
+    var visited = [];
+    var stop = false;
+
+    for (var _iterator2 = queue, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref2;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref2 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref2 = _i2.value;
+      }
+
+      var path = _ref2;
+
+      path.resync();
+
+      if (path.contexts.length === 0 || path.contexts[path.contexts.length - 1] !== this) {
+        path.pushContext(this);
+      }
+
+      if (path.key === null) continue;
+
+      if (testing && queue.length >= 10000) {
+        this.trap = true;
+      }
+
+      if (visited.indexOf(path.node) >= 0) continue;
+      visited.push(path.node);
+
+      if (path.visit()) {
+        stop = true;
+        break;
+      }
+
+      if (this.priorityQueue.length) {
+        stop = this.visitQueue(this.priorityQueue);
+        this.priorityQueue = [];
+        this.queue = queue;
+        if (stop) break;
+      }
+    }
+
+    for (var _iterator3 = queue, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+      var _ref3;
+
+      if (_isArray3) {
+        if (_i3 >= _iterator3.length) break;
+        _ref3 = _iterator3[_i3++];
+      } else {
+        _i3 = _iterator3.next();
+        if (_i3.done) break;
+        _ref3 = _i3.value;
+      }
+
+      var _path = _ref3;
+
+      _path.popContext();
+    }
+
+    this.queue = null;
+
+    return stop;
+  };
+
+  TraversalContext.prototype.visit = function visit(node, key) {
+    var nodes = node[key];
+    if (!nodes) return false;
+
+    if (Array.isArray(nodes)) {
+      return this.visitMultiple(nodes, node, key);
+    } else {
+      return this.visitSingle(node, key);
+    }
+  };
+
+  return TraversalContext;
+}();
+
+exports.default = TraversalContext;
+module.exports = exports["default"];
+}).call(this,require('_process'))
+},{"./path":125,"_process":525,"babel-runtime/core-js/get-iterator":95,"babel-runtime/helpers/classCallCheck":109,"babel-types":151}],117:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var Hub = function Hub(file, options) {
+  (0, _classCallCheck3.default)(this, Hub);
+
+  this.file = file;
+  this.options = options;
+};
+
+exports.default = Hub;
+module.exports = exports["default"];
+},{"babel-runtime/helpers/classCallCheck":109}],118:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.visitors = exports.Hub = exports.Scope = exports.NodePath = undefined;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _path = require("./path");
+
+Object.defineProperty(exports, "NodePath", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_path).default;
+  }
+});
+
+var _scope = require("./scope");
+
+Object.defineProperty(exports, "Scope", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_scope).default;
+  }
+});
+
+var _hub = require("./hub");
+
+Object.defineProperty(exports, "Hub", {
+  enumerable: true,
+  get: function get() {
+    return _interopRequireDefault(_hub).default;
+  }
+});
+exports.default = traverse;
+
+var _context = require("./context");
+
+var _context2 = _interopRequireDefault(_context);
+
+var _visitors = require("./visitors");
+
+var visitors = _interopRequireWildcard(_visitors);
+
+var _babelMessages = require("babel-messages");
+
+var messages = _interopRequireWildcard(_babelMessages);
+
+var _includes = require("lodash/includes");
+
+var _includes2 = _interopRequireDefault(_includes);
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+var _cache = require("./cache");
+
+var cache = _interopRequireWildcard(_cache);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.visitors = visitors;
+function traverse(parent, opts, scope, state, parentPath) {
+  if (!parent) return;
+  if (!opts) opts = {};
+
+  if (!opts.noScope && !scope) {
+    if (parent.type !== "Program" && parent.type !== "File") {
+      throw new Error(messages.get("traverseNeedsParent", parent.type));
+    }
+  }
+
+  visitors.explode(opts);
+
+  traverse.node(parent, opts, scope, state, parentPath);
+}
+
+traverse.visitors = visitors;
+traverse.verify = visitors.verify;
+traverse.explode = visitors.explode;
+
+traverse.NodePath = require("./path");
+traverse.Scope = require("./scope");
+traverse.Hub = require("./hub");
+
+traverse.cheap = function (node, enter) {
+  return t.traverseFast(node, enter);
+};
+
+traverse.node = function (node, opts, scope, state, parentPath, skipKeys) {
+  var keys = t.VISITOR_KEYS[node.type];
+  if (!keys) return;
+
+  var context = new _context2.default(scope, opts, state, parentPath);
+  for (var _iterator = keys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+    var _ref;
+
+    if (_isArray) {
+      if (_i >= _iterator.length) break;
+      _ref = _iterator[_i++];
+    } else {
+      _i = _iterator.next();
+      if (_i.done) break;
+      _ref = _i.value;
+    }
+
+    var key = _ref;
+
+    if (skipKeys && skipKeys[key]) continue;
+    if (context.visit(node, key)) return;
+  }
+};
+
+traverse.clearNode = function (node, opts) {
+  t.removeProperties(node, opts);
+
+  cache.path.delete(node);
+};
+
+traverse.removeProperties = function (tree, opts) {
+  t.traverseFast(tree, traverse.clearNode, opts);
+  return tree;
+};
+
+function hasBlacklistedType(path, state) {
+  if (path.node.type === state.type) {
+    state.has = true;
+    path.stop();
+  }
+}
+
+traverse.hasType = function (tree, scope, type, blacklistTypes) {
+  if ((0, _includes2.default)(blacklistTypes, tree.type)) return false;
+
+  if (tree.type === type) return true;
+
+  var state = {
+    has: false,
+    type: type
+  };
+
+  traverse(tree, {
+    blacklist: blacklistTypes,
+    enter: hasBlacklistedType
+  }, scope, state);
+
+  return state.has;
+};
+
+traverse.clearCache = function () {
+  cache.clear();
+};
+
+traverse.clearCache.clearPath = cache.clearPath;
+traverse.clearCache.clearScope = cache.clearScope;
+
+traverse.copyCache = function (source, destination) {
+  if (cache.path.has(source)) {
+    cache.path.set(destination, cache.path.get(source));
+  }
+};
+},{"./cache":115,"./context":116,"./hub":117,"./path":125,"./scope":137,"./visitors":139,"babel-messages":61,"babel-runtime/core-js/get-iterator":95,"babel-types":151,"lodash/includes":482}],119:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.findParent = findParent;
+exports.find = find;
+exports.getFunctionParent = getFunctionParent;
+exports.getStatementParent = getStatementParent;
+exports.getEarliestCommonAncestorFrom = getEarliestCommonAncestorFrom;
+exports.getDeepestCommonAncestorFrom = getDeepestCommonAncestorFrom;
+exports.getAncestry = getAncestry;
+exports.isAncestor = isAncestor;
+exports.isDescendant = isDescendant;
+exports.inType = inType;
+exports.inShadow = inShadow;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+var _index = require("./index");
+
+var _index2 = _interopRequireDefault(_index);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function findParent(callback) {
+  var path = this;
+  while (path = path.parentPath) {
+    if (callback(path)) return path;
+  }
+  return null;
+}
+
+function find(callback) {
+  var path = this;
+  do {
+    if (callback(path)) return path;
+  } while (path = path.parentPath);
+  return null;
+}
+
+function getFunctionParent() {
+  return this.findParent(function (path) {
+    return path.isFunction() || path.isProgram();
+  });
+}
+
+function getStatementParent() {
+  var path = this;
+  do {
+    if (Array.isArray(path.container)) {
+      return path;
+    }
+  } while (path = path.parentPath);
+}
+
+function getEarliestCommonAncestorFrom(paths) {
+  return this.getDeepestCommonAncestorFrom(paths, function (deepest, i, ancestries) {
+    var earliest = void 0;
+    var keys = t.VISITOR_KEYS[deepest.type];
+
+    for (var _iterator = ancestries, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+      var _ref;
+
+      if (_isArray) {
+        if (_i >= _iterator.length) break;
+        _ref = _iterator[_i++];
+      } else {
+        _i = _iterator.next();
+        if (_i.done) break;
+        _ref = _i.value;
+      }
+
+      var ancestry = _ref;
+
+      var path = ancestry[i + 1];
+
+      if (!earliest) {
+        earliest = path;
+        continue;
+      }
+
+      if (path.listKey && earliest.listKey === path.listKey) {
+        if (path.key < earliest.key) {
+          earliest = path;
+          continue;
+        }
+      }
+
+      var earliestKeyIndex = keys.indexOf(earliest.parentKey);
+      var currentKeyIndex = keys.indexOf(path.parentKey);
+      if (earliestKeyIndex > currentKeyIndex) {
+        earliest = path;
+      }
+    }
+
+    return earliest;
+  });
+}
+
+function getDeepestCommonAncestorFrom(paths, filter) {
+  var _this = this;
+
+  if (!paths.length) {
+    return this;
+  }
+
+  if (paths.length === 1) {
+    return paths[0];
+  }
+
+  var minDepth = Infinity;
+
+  var lastCommonIndex = void 0,
+      lastCommon = void 0;
+
+  var ancestries = paths.map(function (path) {
+    var ancestry = [];
+
+    do {
+      ancestry.unshift(path);
+    } while ((path = path.parentPath) && path !== _this);
+
+    if (ancestry.length < minDepth) {
+      minDepth = ancestry.length;
+    }
+
+    return ancestry;
+  });
+
+  var first = ancestries[0];
+
+  depthLoop: for (var i = 0; i < minDepth; i++) {
+    var shouldMatch = first[i];
+
+    for (var _iterator2 = ancestries, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+      var _ref2;
+
+      if (_isArray2) {
+        if (_i2 >= _iterator2.length) break;
+        _ref2 = _iterator2[_i2++];
+      } else {
+        _i2 = _iterator2.next();
+        if (_i2.done) break;
+        _ref2 = _i2.value;
+      }
+
+      var ancestry = _ref2;
+
+      if (ancestry[i] !== shouldMatch) {
+        break depthLoop;
+      }
+    }
+
+    lastCommonIndex = i;
+    lastCommon = shouldMatch;
+  }
+
+  if (lastCommon) {
+    if (filter) {
+      return filter(lastCommon, lastCommonIndex, ancestries);
+    } else {
+      return lastCommon;
+    }
+  } else {
+    throw new Error("Couldn't find intersection");
+  }
+}
+
+function getAncestry() {
+  var path = this;
+  var paths = [];
+  do {
+    paths.push(path);
+  } while (path = path.parentPath);
+  return paths;
+}
+
+function isAncestor(maybeDescendant) {
+  return maybeDescendant.isDescendant(this);
+}
+
+function isDescendant(maybeAncestor) {
+  return !!this.findParent(function (parent) {
+    return parent === maybeAncestor;
+  });
+}
+
+function inType() {
+  var path = this;
+  while (path) {
+    for (var _iterator3 = arguments, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
+      var _ref3;
+
+      if (_isArray3) {
+        if (_i3 >= _iterator3.length) break;
+        _ref3 = _iterator3[_i3++];
+      } else {
+        _i3 = _iterator3.next();
+        if (_i3.done) break;
+        _ref3 = _i3.value;
+      }
+
+      var type = _ref3;
+
+      if (path.node.type === type) return true;
+    }
+    path = path.parentPath;
+  }
+
+  return false;
+}
+
+function inShadow(key) {
+  var parentFn = this.isFunction() ? this : this.findParent(function (p) {
+    return p.isFunction();
+  });
+  if (!parentFn) return;
+
+  if (parentFn.isFunctionExpression() || parentFn.isFunctionDeclaration()) {
+    var shadow = parentFn.node.shadow;
+
+    if (shadow && (!key || shadow[key] !== false)) {
+      return parentFn;
+    }
+  } else if (parentFn.isArrowFunctionExpression()) {
+    return parentFn;
+  }
+
+  return null;
+}
+},{"./index":125,"babel-runtime/core-js/get-iterator":95,"babel-types":151}],120:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.shareCommentsWithSiblings = shareCommentsWithSiblings;
+exports.addComment = addComment;
+exports.addComments = addComments;
+function shareCommentsWithSiblings() {
+  if (typeof this.key === "string") return;
+
+  var node = this.node;
+  if (!node) return;
+
+  var trailing = node.trailingComments;
+  var leading = node.leadingComments;
+  if (!trailing && !leading) return;
+
+  var prev = this.getSibling(this.key - 1);
+  var next = this.getSibling(this.key + 1);
+
+  if (!prev.node) prev = next;
+  if (!next.node) next = prev;
+
+  prev.addComments("trailing", leading);
+  next.addComments("leading", trailing);
+}
+
+function addComment(type, content, line) {
+  this.addComments(type, [{
+    type: line ? "CommentLine" : "CommentBlock",
+    value: content
+  }]);
+}
+
+function addComments(type, comments) {
+  if (!comments) return;
+
+  var node = this.node;
+  if (!node) return;
+
+  var key = type + "Comments";
+
+  if (node[key]) {
+    node[key] = node[key].concat(comments);
+  } else {
+    node[key] = comments;
+  }
+}
+},{}],121:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+exports.call = call;
+exports._call = _call;
+exports.isBlacklisted = isBlacklisted;
+exports.visit = visit;
+exports.skip = skip;
+exports.skipKey = skipKey;
+exports.stop = stop;
+exports.setScope = setScope;
+exports.setContext = setContext;
+exports.resync = resync;
+exports._resyncParent = _resyncParent;
+exports._resyncKey = _resyncKey;
+exports._resyncList = _resyncList;
+exports._resyncRemoved = _resyncRemoved;
+exports.popContext = popContext;
+exports.pushContext = pushContext;
+exports.setup = setup;
+exports.setKey = setKey;
+exports.requeue = requeue;
+exports._getQueueContexts = _getQueueContexts;
+
+var _index = require("../index");
+
+var _index2 = _interopRequireDefault(_index);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function call(key) {
+  var opts = this.opts;
+
+  this.debug(function () {
+    return key;
+  });
+
+  if (this.node) {
+    if (this._call(opts[key])) return true;
+  }
+
+  if (this.node) {
+    return this._call(opts[this.node.type] && opts[this.node.type][key]);
+  }
+
+  return false;
+}
+
+function _call(fns) {
+  if (!fns) return false;
+
+  for (var _iterator = fns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+    var _ref;
+
+    if (_isArray) {
+      if (_i >= _iterator.length) break;
+      _ref = _iterator[_i++];
+    } else {
+      _i = _iterator.next();
+      if (_i.done) break;
+      _ref = _i.value;
+    }
+
+    var fn = _ref;
+
+    if (!fn) continue;
+
+    var node = this.node;
+    if (!node) return true;
+
+    var ret = fn.call(this.state, this, this.state);
+    if (ret) throw new Error("Unexpected return value from visitor method " + fn);
+
+    if (this.node !== node) return true;
+
+    if (this.shouldStop || this.shouldSkip || this.removed) return true;
+  }
+
+  return false;
+}
+
+function isBlacklisted() {
+  var blacklist = this.opts.blacklist;
+  return blacklist && blacklist.indexOf(this.node.type) > -1;
+}
+
+function visit() {
+  if (!this.node) {
+    return false;
+  }
+
+  if (this.isBlacklisted()) {
+    return false;
+  }
+
+  if (this.opts.shouldSkip && this.opts.shouldSkip(this)) {
+    return false;
+  }
+
+  if (this.call("enter") || this.shouldSkip) {
+    this.debug(function () {
+      return "Skip...";
+    });
+    return this.shouldStop;
+  }
+
+  this.debug(function () {
+    return "Recursing into...";
+  });
+  _index2.default.node(this.node, this.opts, this.scope, this.state, this, this.skipKeys);
+
+  this.call("exit");
+
+  return this.shouldStop;
+}
+
+function skip() {
+  this.shouldSkip = true;
+}
+
+function skipKey(key) {
+  this.skipKeys[key] = true;
+}
+
+function stop() {
+  this.shouldStop = true;
+  this.shouldSkip = true;
+}
+
+function setScope() {
+  if (this.opts && this.opts.noScope) return;
+
+  var target = this.context && this.context.scope;
+
+  if (!target) {
+    var path = this.parentPath;
+    while (path && !target) {
+      if (path.opts && path.opts.noScope) return;
+
+      target = path.scope;
+      path = path.parentPath;
+    }
+  }
+
+  this.scope = this.getScope(target);
+  if (this.scope) this.scope.init();
+}
+
+function setContext(context) {
+  this.shouldSkip = false;
+  this.shouldStop = false;
+  this.removed = false;
+  this.skipKeys = {};
+
+  if (context) {
+    this.context = context;
+    this.state = context.state;
+    this.opts = context.opts;
+  }
+
+  this.setScope();
+
+  return this;
+}
+
+function resync() {
+  if (this.removed) return;
+
+  this._resyncParent();
+  this._resyncList();
+  this._resyncKey();
+}
+
+function _resyncParent() {
+  if (this.parentPath) {
+    this.parent = this.parentPath.node;
+  }
+}
+
+function _resyncKey() {
+  if (!this.container) return;
+
+  if (this.node === this.container[this.key]) return;
+
+  if (Array.isArray(this.container)) {
+    for (var i = 0; i < this.container.length; i++) {
+      if (this.container[i] === this.node) {
+        return this.setKey(i);
+      }
+    }
+  } else {
+    for (var key in this.container) {
+      if (this.container[key] === this.node) {
+        return this.setKey(key);
+      }
+    }
+  }
+
+  this.key = null;
+}
+
+function _resyncList() {
+  if (!this.parent || !this.inList) return;
+
+  var newContainer = this.parent[this.listKey];
+  if (this.container === newContainer) return;
+
+  this.container = newContainer || null;
+}
+
+function _resyncRemoved() {
+  if (this.key == null || !this.container || this.container[this.key] !== this.node) {
+    this._markRemoved();
+  }
+}
+
+function popContext() {
+  this.contexts.pop();
+  this.setContext(this.contexts[this.contexts.length - 1]);
+}
+
+function pushContext(context) {
+  this.contexts.push(context);
+  this.setContext(context);
+}
+
+function setup(parentPath, container, listKey, key) {
+  this.inList = !!listKey;
+  this.listKey = listKey;
+  this.parentKey = listKey || key;
+  this.container = container;
+
+  this.parentPath = parentPath || this.parentPath;
+  this.setKey(key);
+}
+
+function setKey(key) {
+  this.key = key;
+  this.node = this.container[this.key];
+  this.type = this.node && this.node.type;
+}
+
+function requeue() {
+  var pathToQueue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this;
+
+  if (pathToQueue.removed) return;
+
+  var contexts = this.contexts;
+
+  for (var _iterator2 = contexts, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+    var _ref2;
+
+    if (_isArray2) {
+      if (_i2 >= _iterator2.length) break;
+      _ref2 = _iterator2[_i2++];
+    } else {
+      _i2 = _iterator2.next();
+      if (_i2.done) break;
+      _ref2 = _i2.value;
+    }
+
+    var context = _ref2;
+
+    context.maybeQueue(pathToQueue);
+  }
+}
+
+function _getQueueContexts() {
+  var path = this;
+  var contexts = this.contexts;
+  while (!contexts.length) {
+    path = path.parentPath;
+    contexts = path.contexts;
+  }
+  return contexts;
+}
+},{"../index":118,"babel-runtime/core-js/get-iterator":95}],122:[function(require,module,exports){
+"use strict";
+
+exports.__esModule = true;
+exports.toComputedKey = toComputedKey;
+exports.ensureBlock = ensureBlock;
+exports.arrowFunctionToShadowed = arrowFunctionToShadowed;
+
+var _babelTypes = require("babel-types");
+
+var t = _interopRequireWildcard(_babelTypes);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function toComputedKey() {
+  var node = this.node;
+
+  var key = void 0;
+  if (this.isMemberExpression()) {
+    key = node.property;
+  } else if (this.isProperty() || this.isMethod()) {
+    key = node.key;
+  } else {
+    throw new ReferenceError("todo");
+  }
+
+  if (!node.computed) {
+    if (t.isIdentifier(key)) key = t.stringLiteral(key.name);
+  }
+
+  return key;
+}
+
+function ensureBlock() {
+  return t.ensureBlock(this.node);
+}
+
+function arrowFunctionToShadowed() {
+  if (!this.isArrowFunctionExpression()) return;
+
+  this.ensureBlock();
+
+  var node = this.node;
+
+  node.expression = false;
+  node.type = "FunctionExpression";
+  node.shadow = node.shadow || true;
+}
+},{"babel-types":151}],123:[function(require,module,exports){
+(function (global){
+"use strict";
+
+exports.__esModule = true;
+
+var _typeof2 = require("babel-runtime/helpers/typeof");
+
+var _typeof3 = _interopRequireDefault(_typeof2);
+
+var _getIterator2 = require("babel-runtime/core-js/get-iterator");
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _map = require("babel-runtime/core-js/map");
+
+var _map2 = _interopRequireDefault(_map);
+
+exports.evaluateTruthy = evaluateTruthy;
+exports.evaluate = evaluate;
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var VALID_CALLEES = ["String", "Number", "Math"];
+var INVALID_METHODS = ["random"];
+
+function evaluateTruthy() {
+  var res = this.evaluate();
+  if (res.confident) return !!res.value;
+}
+
+function evaluate() {
+  var confident = true;
+  var deoptPath = void 0;
+  var seen = new _map2.default();
+
+  function deopt(path) {
+    if (!confident) return;
+    deoptPath = path;
+    confident = false;
+  }
+
+  var value = evaluate(this);
+  if (!confident) value = undefined;
+  return {
+    confident: confident,
+    deopt: deoptPath,
+    value: value
+  };
+
+  function evaluate(path) {
+    var node = path.node;
+
+
+    if (seen.has(node)) {
+      var existing = seen.get(node);
+      if (existing.resolved) {
+        return existing.value;
+      } else {
+        deopt(path);
+        return;
+      }
+    } else {
+      var item = { resolved: false };
+      seen.set(node, item);
+
+      var val = _evaluate(path);
+      if (confident) {
+        item.resolved = true;
+        item.value = val;
+      }
+      return val;
+    }
+  }
+
+  function _evaluate(path) {
+    if (!confident) return;
+
+    var node = path.node;
+
+
+    if (path.isSequenceExpression()) {
+      var exprs = path.get("expressions");
+      return evaluate(exprs[exprs.length - 1]);
+    }
+
+    if (path.isStringLiteral() || path.isNumericLiteral() || path.isBooleanLiteral()) {
+      return node.value;
+    }
+
+    if (path.isNullLiteral()) {
+      return null;
+    }
+
+    if (path.isTemplateLiteral()) {
+      var str = "";
+
+      var i = 0;
+      var _exprs = path.get("expressions");
+
+      for (var _iterator = node.quasis, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
+        var _ref;
+
+        if (_isArray) {
+          if (_i >= _iterator.length) break;
+          _ref = _iterator[_i++];
+        } else {
+          _i = _iterator.next();
+          if (_i.done) break;
+          _ref = _i.value;
+        }
+
+        var elem = _ref;
+
+        if (!confident) break;
+
+        str += elem.value.cooked;
+
+        var expr = _exprs[i++];
+        if (expr) str += String(evaluate(expr));
+      }
+
+      if (!confident) return;
+      return str;
+    }
+
+    if (path.isConditionalExpression()) {
+      var testResult = evaluate(path.get("test"));
+      if (!confident) return;
+      if (testResult) {
+        return evaluate(path.get("consequent"));
+      } else {
+        return evaluate(path.get("alternate"));
+      }
+    }
+
+    if (path.isExpressionWrapper()) {
+      return evaluate(path.get("expression"));
+    }
+
+    if (path.isMemberExpression() && !path.parentPath.isCallExpression({ callee: node })) {
+      var property = path.get("property");
+      var object = path.get("object");
+
+      if (object.isLiteral() && property.isIdentifier()) {
+        var _value = object.node.value;
+        var type = typeof _value === "undefined" ? "undefined" : (0, _typeof3.default)(_value);
+        if (type === "number" || type === "string") {
+          return _value[property.node.name];
+        }
+      }
+    }
+
+    if (path.isReferencedIdentifier()) {
+      var binding = path.scope.getBinding(node.name);
+
+      if (binding && binding.constantViolations.length > 0) {
+        return deopt(binding.path);
+      }
+
+      if (binding && path.node.start < binding.path.node.end) {
+        return deopt(binding.path);
+      }
+
+      if (binding && binding.hasValue) {
+        return binding.value;
+      } else {
+        if (node.name === "undefined") {
+          return binding ? deopt(binding.path) : undefined;
+        } else if (node.name === "Infinity") {
+          return binding ? deopt(binding.path) : Infinity;
+        } else if (node.name === "NaN") {
+          return binding ? deopt(binding.path) : NaN;
+        }
+
+        var resolved = path.resolve();
+        if (resolved === path) {
+          return deopt(path);
+        } else {
+          return evaluate(resolved);
+        }
+      }
+    }
+
+    if (path.isUnaryExpression({ prefix: true })) {
+      if (node.operator === "void") {
+        return undefined;
+      }
+
+      var argument = path.get("argument");
+      if (node.operator === "typeof" && (argument.isFunction() || argument.isClass())) {
+        return "function";
+      }
+
+      var arg = evaluate(argument);
+      if (!confident) return;
+      switch (node.operator) {
+        case "!":
+          return !arg;
+        case "+":
+          return +arg;
+        case "-":
+          return -arg;
+        case "~":
+          return ~arg;
+        case "typeof":
+          return typeof arg === "undefined" ? "undefined" : (0, _typeof3.default)(arg);
+      }
+    }
+
+    if (path.isArrayExpression()) {
+      var arr = [];
+      var elems = path.get("elements");
+      for (var _iterator2 = elems, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
+        var _ref2;
+
+        if (_isArray2) {
+          if (_i2 >= _iterator2.length) break;
+          _ref2 = _iterator2[_i2++];
+        } else {
+          _i2 = _iterator2.next();
+          if (_i2.done) break;
+          _ref2 = _i2.value;
+        }
+
+        var _elem = _ref2;
+
+        _elem = _elem.evaluate();
+
+        if (_elem.confident) {
+          arr.push(_elem.value);
+        } else {
+          return deopt(_elem);
+        }
+      }
+      return arr;
+    }
+
+    if (path.isObjectExpression()) {
+      var obj = {};
+      var props = path.get("properties");
+      for (var _iterator3 = props, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 